codex-storage / codex-contracts-eth Goto Github PK
View Code? Open in Web Editor NEWEthereum smart contracts for Codex
License: Other
Ethereum smart contracts for Codex
License: Other
Deploy the smart contracts on an L2 testnet, to support the Codex testnet and allow for performance measurements.
Currently, if a node fills a slot and the request successfully finishes, it gets paid for the entire request duration regardless of when the node actually filled the slot.
In the context of Slot Reservations, we proposed that changing this behavior to payment based on the actual time of slot filling would create a small incentive to fill the slot as soon as possible.
There should be this check in fillSlot
: https://github.com/codex-storage/codex-contracts-eth/blob/master/contracts/Marketplace.sol#L113
During writing Application Properties for Certora integration, I am slowly discovering a lot of small things that should be fixed, but maybe not necessarily need a whole issue. I will dump them here and afterwards fix them.
Create RequestId
, SlotId
, LockId
, ProofId
, EndId
types to avoid confusion and enforce compiler restrictions.
This issue is about implementing the application property that only certain state transitions of SlotState
and RequestState
are allowed.
Exact details of this issue will be worked out with the smart contracts team and certora.
Per our team call on Thursday, I started working out the details for deploying the contracts in this repo to our POA test network.
I'm familiar with all the concepts; but if it seems like there's something obvious I missed, please point it out because it probably isn't obvious to me. To date, I haven't spent much time with contracts, deployments, etc.
My first goal is to "get it right". After that I can tie into ansible/terraform automation, if that's the thing to do; or maybe it will be a one-off deployment for now, i.e. for the sake of the demo.
Outline of my approach:
Setup a local POA network. I found a helpful tutorial and followed it, starting with the linked Create Validator Accounts section (I had already downloaded geth
v1.10.17 on my mac and put it in PATH
).
Deploy dagger-contracts to my local POA network. Hardhat's docs were helpful for this step. It works!
Run nim-dagger's testContracts
against my local POA network. I don't think we want/need to run those tests against the infra-codex network, but getting them to pass locally with geth
seems like a good way to gain confidence things will work as intended. I'm currently stuck on this step.
Prep to deploy on the infra-codex POA network.
For step 2 I have this in a clone of status-im/dagger-contracts:
hardhat.config_poa.js
require("@nomiclabs/hardhat-waffle")
require("hardhat-deploy")
require("hardhat-deploy-ethers")
// keys for two funded accounts that are unlocked on both nodes in my local POA network
const LOCALPOA_PRIVATE_KEYS = [
...,
...
]
module.exports = {
solidity: "0.8.4",
networks: {
"2337": {
url: "http://127.0.0.1:8545",
accounts: LOCALPOA_PRIVATE_KEYS
}
}
}
scripts/deploy.js
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with the account:", deployer.address);
console.log("Account balance:", (await deployer.getBalance()).toString());
const TestToken = await ethers.getContractFactory("TestToken");
const testToken = await TestToken.deploy();
console.log("TestToken address:", testToken.address);
const token = testToken.address;
const proofPeriod = 10;
const proofTimeout = 5;
const proofDowntime = 64;
const collateralAmount = 100;
const slashMisses = 3;
const slashPercentage = 10;
const Storage = await ethers.getContractFactory("Storage");
const storage = await Storage.deploy(token, proofPeriod, proofTimeout,
proofDowntime, collateralAmount, slashMisses, slashPercentage);
console.log("Storage address:", storage.address);
const file = "./deployment-localhost.json";
const fs = require("fs/promises");
let deployment = JSON.parse((await fs.readFile(file)).toString());
deployment.name = "localpoa";
deployment.chainId = "2337";
deployment.contracts.TestToken.address = testToken.address;
deployment.contracts.Storage.address = storage.address;
await fs.writeFile(file, JSON.stringify(deployment, null, 2));
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
First I run npm start
so that deployment-localhost.json
gets written to disk. After stopping the Hardhat process and firing up my geth
nodes, I run:
$ ./node_modules/.bin/hardhat run scripts/deploy.js --config ./hardhat.config_poa.js --network 2337
For step 3, I copy the updated deployment-localhost.json
to e.g. ~/repos/nim-dagger/vendor/dagger-contracts/
I have these changes in nim-dagger:
modified tests/contracts/ethertest.nim
@@ -37,11 +37,12 @@ template ethersuite*(name, body) =
setup:
provider = JsonRpcProvider.new("ws://localhost:8545")
- snapshot = await send(provider, "evm_snapshot")
+ # snapshot = await send(provider, "evm_snapshot")
accounts = await provider.listAccounts()
teardown:
- discard await send(provider, "evm_revert", @[snapshot])
+ # discard await send(provider, "evm_revert", @[snapshot])
+ discard
body
At the moment I'm stuck. For many (though not all) contract calls in testContracts
I'm getting this error:
{"code": -32602, "message": "missing value for required argument 1"}
I did not encounter that error when running testContracts
against a local Hardhat environment, and haven't seen it in CI, which also uses Hardhat.
I'm wondering if it's related to this:
ethereum/go-ethereum#2472
ethereum/go-ethereum#2473
My theory is that nim-ethers isn't passing the default block parameter for some methods, and while that's not a problem for Hardhat it is a problem for Go Ethereum.
I'll attempt to modify nim-ethers and check if my theory holds up.
Any thoughts on whether the error is being caused by something else?
For the deployment on infra-codex, I could simply run scripts/deploy.js
(with appropriate changes) from within vendor/dagger-contracts
of one of the codex nodes and make note of the contract addresses.
Would that be sufficient for now, or do we want to automate the process somehow? Please let me know your ideas and suggestions.
We also need to think about how to supply the addresses to the codex nodes. Would it be better to supply them in a CLI parameter/s when starting a node, or should they be baked into the builds?
This issue is about implementing the relational rules for various mappings that live in MarketPlace
and Proofs
.
Exact details of this issue will be worked out with the smart contracts team and certora.
Once #113 has landed we can start taking existing fuzz tests and move them over to certora rules.
We need to check how many tests there are. If it's too many we'll break this issue down into smaller chunks.
This should be considered as a part of codex-storage/infra-codex/issues/186 and quick workaround for #112.
We would need to deploy an updated version of the Marketplace smart contract on existing Testnet before the EthCC, without changing anything around.
Plan is the following
devnet-testnet
until we will finish #112codexdisttestnetwork
because it was used for previous deployment on Testnet/hardhat/deployments/codexdisttestnetwork
folder content, excluding Marketplace.json
Marketplace.json
from the new deployment to the branchCurrently, as described in #43 the money put into a Request by the Client is paid out to Hosts when the Request is canceled because of timeout. Instead, the money should be split between Hosts and Client based on the time for how long Hosts stored the content before the Request was pronounced to be timed out and the rest paid out to the Client.
Currently, we use a placeholder for checking storage proofs. This needs to be replaced by an actual storage proof check.
The current logic for expecting proofs (in expectProofs
) starts when a slot is filled and ends at the block.timestamp + duration
. This ending will be different for each slot, as each slot will likely be filled at different times, and all slots except the last will not be expected to provide proofs up until the point that the contract is finished. The ending should likely instead be contractStartTime + duration
. Currently, we don't track contractStartTime
, so proof expectations will need to be extended (like lock expiry) once all slots are filled.
codex-contracts-eth/contracts/Proofs.sol
Line 40 in 57e8cd5
When a Request is canceled because of time out (after the Client calls the withdrawFunction
, which returns him all the money for the original Request), then hosts that have already filled some slots can call freeSlot
which pays them out the money for the slot. This makes the contract's money pool out of balance as the money is already returned to the Client in the withdrawFunction
.
There is a plan in the future to take into consideration the time for how long was the content hosted and return only a partial reward to the client and a partial reward for the hosts, but until then this needs to be fixed.
The probably easiest solution is to payout filled slots to host for now.
This issue is about implementing the application property that certain state transitions of SlotState
and RequestState
are only allowed by certain function calls.
Exact details of this issue will be worked out with the smart contracts team and certora.
As Ethereum 2 validators have several addresses, maybe the Codex node could have a "reward address"?
Implementation of the expanding window mechanism, as defined in the slot reservations PR: https://github.com/codex-storage/codex-research/pull/190/files#diff-fa2b9edd6a6c8a82c8c3e42738f743b760d80f197982d9442e2b6e67f39cdc7dR52-R86
Subtasks:
The _getPointer
function can reduce the number of % 256
's to reduce gas consumption:
Proofs.sol
- function _getPointer(SlotId id, Period period) internal view returns (uint8) {
- uint256 blockNumber = block.number % 256;
- // To ensure the pointer does not remain in downtime for many consecutive
- // periods, for each period increase, move the pointer 67 blocks. We've
- // chosen a prime number to ensure that we don't get cycles.
- uint256 periodNumber = (Period.unwrap(period) * 67) % 256;
- uint256 idOffset = uint256(SlotId.unwrap(id)) % 256;
- uint256 pointer = (blockNumber + periodNumber + idOffset) % 256;
- return uint8(pointer);
- }
+ function _getPointer(SlotId id, Period period) internal view returns (uint8) {
+ uint256 blockNumber = block.number;
+ // To ensure the pointer does not remain in downtime for many consecutive
+ // periods, for each period increase, move the pointer 67 blocks. We've
+ // chosen a prime number to ensure that we don't get cycles.
+ uint256 periodNumber = (Period.unwrap(period) * 67);
+ uint256 idOffset = uint256(SlotId.unwrap(id));
+ uint256 pointer = (blockNumber + periodNumber + idOffset) % 256;
+ return uint8(pointer);
+ }
Currently, the fuzzing tests does not take in consideration time, which is for example required to tests expired requests.
As we discussed, we should introduce testnet
for Codex Testnet and that require some modificaitons
hardhat.config.js
verifier/networks
We discussed the name testnet
, but shouldn't codex_testnet
be more appropriate similar to taiko_test
?
Part of https://github.com/codex-storage/infra-codex/issues/186
In case of an emergency, eg an exploit, admins should be able to freeze a contract, allowing only withdrawing of funds from the contract.
Freezing a contract will be the only functionality of an admin.
Once a contract is frozen, only withdrawal functionality would be enabled. This includes:
freeSlot
withdrawFunds
We should keep in mind that in normal operation, withdrawal txs (eg freeSlot
, withdrawFunds
) are only allowed when a request is cancelled or finished. Therefore, freezing a contract should disable these checks.
These additions should be done pre-audit.
This issue is about implementing the application property that the marketplace owns enough funds to pay back its storage requesters and storage providers.
Exact details of this issue will be worked out with the smart contracts team and certora.
When a contract completes (succeeds or fails), send client remaining funds.
When a slot is filled, the proof probability is stored in a private mapping _probabilities
. However, this is likely not needed as the proof probability for a Request
is already stored in Request.Ask
.
This may require passing in the request Id.
Currently in the markProofAsMissing
there is no reward for the node that calls this function correctly.
It is a question when and whom should get paid the reward as not every call to markProofAsMissing
leads to slashing (from which the funds for reward could be deducted) and in the same time if only those calls that leads to slashing will yield the reward, then there is no incentive to really call this function for the other cases...
Currently, the minimum required collateral is defined on the smart-contract level as an absolute value. Repair reward is currently not defined. And the slashing is logarithmic.
We have agreed to replace the minimumAmount
with number of slashing. There needs to be a check for numberOfSlashing*slashingPercentage<=100
, though. Also we have decided to move from logarithmic to linear slashing, which goes in hand with the previous change.
https://github.com/codex-storage/codex-contracts-eth/blob/master/contracts/Proofs.sol#L48
The Period multiplicator (67) in getPointer()
function should be configurable as it is coupled with the downtime parameter.
We should also better understand what configuration values we will use in real deployment, because then maybe we would not even need the multiplication? I would assume that the Period should be quite long, but Mark pointed out that it should not be longer than the 256 blocks window.
The dispersal parameter can set the rate of dispersal, a mechanism to elect what percentage of addresses are eligible in the expanding window at the halfway point to contract expiry.
initial definition
https://github.com/codex-storage/codex-research/blob/master/design/marketplace.md#dispersal
revised definition
https://github.com/codex-storage/codex-research/pull/190/files#diff-fa2b9edd6a6c8a82c8c3e42738f743b760d80f197982d9442e2b6e67f39cdc7dR76-R86
When we want to migrate our smart contracts, we need the ability to deprecate the old contract but it needs to be alive until the last Request finishes/fails/cancelles. We should hence prevent somebody from creating very long contracts which would hinder this process and hence have an upper limit for the Request's duration.
What would be a reasonable limit? 6 months? 3 months?
We should do some validation on the inputted Request, mainly that all the values are specified (non-zero) and possibly some more.
Currently, when a slot is freed and another host repairs it, they receive the repair reward. Upon successfully completing the slot, they will receive the reward for the entire storage contract duration, not just a portion based on how long they filled the slot (e.g., from the time of slot repair).
Is this desirable? Could it pose a problem?
This issue is about implementing the application property that a host can not receive a payment for its work twice.
Exact details of this rule will be worked out with the smart contracts team and certora
Currently, a host puts down collateral once, which allows it to fill slots in many storage contracts. We'd like to change that to a (smaller) collateral per slot that the host fills. That collateral is then specifically meant to cover risks associated with that slot.
Rationale and design:
https://github.com/status-im/codex-research/blob/main/design/marketplace.md
A marketplace test suite should be created that uses the real proof verifier contract, instead of the test contract. This will serve two purposes:
hardhat-gas-reporter
when running the tests with REPORT_GAS
Currently the Request
object has client
property which is now enforced that it must be the msg.sender
(here and is not allowed to be specified to some different address, hence it would be simpler to drop the Request.client
property and instead use the msg.sender
which could be stored in the RequestContext
object.
This issue is about implementing the application property that a state transition of SlotState
and RequestState
cannot happen more than once in any given function call of the contract.
Exact details of this issue will be worked out with the smart contracts team and certora.
This issue is about implementing the application property that the marketplace totals sent
value is always <= its totals received
value.
Exact details of this issue will be worked out with the smart contracts team and certora.
I got a new machine recently and have been setting up my dev environment again. When I run npm install
on the codex master branch with node 18.15.0 I'm getting build errors. I've added the errors below for others to find.
It appears to be due to my Python version which is Python 3.12 which doesn't bundle distutils
by default anymore.
I was able to resolve the issue by running brew install python-setuptools
. You can see stackoverflow for more info.
Unfortunately I'm not aware of how to resolve this for all users. Possibly updating some node deps would use updated python dependencies (gotta love rabbit trails ;)). Otherwise it might make sense to add a note in Codex or here.
npm ERR! code 1
npm ERR! path /Users/elcritch/projs/status/nim-codex/vendor/codex-contracts-eth/node_modules/ganache-core/node_modules/utf-8-validate
npm ERR! command failed
npm ERR! command sh -c node-gyp-build
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using [email protected]
npm ERR! gyp info using [email protected] | darwin | arm64
npm ERR! gyp info find Python using Python version 3.12.2 found at "/opt/homebrew/opt/[email protected]/bin/python3.12"
npm ERR! gyp info spawn /opt/homebrew/opt/[email protected]/bin/python3.12
npm ERR! gyp info spawn args [
npm ERR! gyp info spawn args '/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
npm ERR! gyp info spawn args 'binding.gyp',
npm ERR! gyp info spawn args '-f',
npm ERR! gyp info spawn args 'make',
npm ERR! gyp info spawn args '-I',
npm ERR! gyp info spawn args '/Users/elcritch/projs/status/nim-codex/vendor/codex-contracts-eth/node_modules/ganache-core/node_modules/utf-8-validate/build/config.gypi',
npm ERR! gyp info spawn args '-I',
npm ERR! gyp info spawn args '/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
npm ERR! gyp info spawn args '-I',
npm ERR! gyp info spawn args '/Users/elcritch/Library/Caches/node-gyp/18.15.0/include/node/common.gypi',
npm ERR! gyp info spawn args '-Dlibrary=shared_library',
npm ERR! gyp info spawn args '-Dvisibility=default',
npm ERR! gyp info spawn args '-Dnode_root_dir=/Users/elcritch/Library/Caches/node-gyp/18.15.0',
npm ERR! gyp info spawn args '-Dnode_gyp_dir=/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp',
npm ERR! gyp info spawn args '-Dnode_lib_file=/Users/elcritch/Library/Caches/node-gyp/18.15.0/<(target_arch)/node.lib',
npm ERR! gyp info spawn args '-Dmodule_root_dir=/Users/elcritch/projs/status/nim-codex/vendor/codex-contracts-eth/node_modules/ganache-core/node_modules/utf-8-validate',
npm ERR! gyp info spawn args '-Dnode_engine=v8',
npm ERR! gyp info spawn args '--depth=.',
npm ERR! gyp info spawn args '--no-parallel',
npm ERR! gyp info spawn args '--generator-output',
npm ERR! gyp info spawn args 'build',
npm ERR! gyp info spawn args '-Goutput_dir=.'
npm ERR! gyp info spawn args ]
npm ERR! Traceback (most recent call last):
npm ERR! File "/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py", line 42, in <module>
npm ERR! import gyp # noqa: E402
npm ERR! ^^^^^^^^^^
npm ERR! File "/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/__init__.py", line 9, in <module>
npm ERR! import gyp.input
npm ERR! File "/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/input.py", line 19, in <module>
npm ERR! from distutils.version import StrictVersion
npm ERR! ModuleNotFoundError: No module named 'distutils'
npm ERR! gyp ERR! configure error
npm ERR! gyp ERR! stack Error: `gyp` failed with exit code: 1
npm ERR! gyp ERR! stack at ChildProcess.onCpExit (/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:325:16)
npm ERR! gyp ERR! stack at ChildProcess.emit (node:events:513:28)
npm ERR! gyp ERR! stack at ChildProcess._handle.onexit (node:internal/child_process:291:12)
npm ERR! gyp ERR! System Darwin 23.3.0
npm ERR! gyp ERR! command "/Users/elcritch/.asdf/installs/nodejs/18.15.0/bin/node" "/Users/elcritch/.asdf/installs/nodejs/18.15.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
npm ERR! gyp ERR! cwd /Users/elcritch/projs/status/nim-codex/vendor/codex-contracts-eth/node_modules/ganache-core/node_modules/utf-8-validate
npm ERR! gyp ERR! node -v v18.15.0
npm ERR! gyp ERR! node-gyp -v v9.3.1
npm ERR! gyp ERR! not ok
Environment details:
OS: macOS 14.3.1 m3
python: 3.12
node: 18.15.0
This issue is about implementing the application property that the number of _missed
proofs for certain slot IDs is less or equal to the number of periods with missed proofs.
Exact details of this issue will be worked out with the smart contracts team and certora.
This would prevent all the potential overflow scenario and potentially other bugs:
As of hardhat v2.18, the preferred deployment methodology is to use their new Ignition module, instead of the hardhat-deploy
plugin. Our deployments will need to be migrated to support this. Additionally, I believe this requires updating ethers to v6.
This issue is about implementing the application property that a host can not gain more rewards for their work than what was specified in the storage request that another node has put out.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.