local-marketplace.md
1 --- 2 outline: [2, 3] 3 --- 4 # Running a Local Codex Network with Marketplace Support 5 6 This tutorial will teach you how to run a small Codex network with the 7 _storage marketplace_ enabled; i.e., the functionality in Codex which 8 allows participants to offer and buy storage in a market, ensuring that 9 storage providers honor their part of the deal by means of cryptographic proofs. 10 11 In this tutorial, you will: 12 13 1. [Set Up a Geth PoA network](#_1-set-up-a-geth-poa-network); 14 2. [Set up The Marketplace](#_2-set-up-the-marketplace); 15 3. [Run Codex](#_3-run-codex); 16 4. [Buy and Sell Storage in the Marketplace](#_4-buy-and-sell-storage-on-the-marketplace). 17 18 ## Prerequisites 19 20 To complete this tutorial, you will need: 21 22 * the [geth](https://github.com/ethereum/go-ethereum) Ethereum client; 23 You need version `1.13.x` of geth as newer versions no longer support 24 Proof of Authority (PoA). This tutorial was tested using geth version `1.13.15`. 25 * a Codex binary, which [you can compile from source](https://github.com/codex-storage/nim-codex?tab=readme-ov-file#build-and-run). 26 27 We will also be using [bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) 28 syntax throughout. If you use a different shell, you may need to adapt 29 things to your platform. 30 31 To get started, create a new folder where we will keep the tutorial-related 32 files so that we can keep them separate from the codex repository. 33 We assume the name of the folder to be `marketplace-tutorial`. 34 35 ## 1. Set Up a Geth PoA Network 36 37 For this tutorial, we will use a simple 38 [Proof-of-Authority](https://github.com/ethereum/EIPs/issues/225) network 39 with geth. The first step is creating a _signer account_: an account which 40 will be used by geth to sign the blocks in the network. 41 Any block signed by a signer is accepted as valid. 42 43 ### 1.1. Create a Signer Account 44 45 To create a signer account, from the `marketplace-tutorial` directory run: 46 47 ```bash 48 geth account new --datadir geth-data 49 ``` 50 51 The account generator will ask you to input a password, which you can 52 leave blank. It will then print some information, 53 including the account's public address: 54 55 ```bash 56 INFO [09-29|16:49:24.244] Maximum peer count ETH=50 total=50 57 Your new account is locked with a password. Please give a password. Do not forget this password. 58 Password: 59 Repeat password: 60 61 Your new key was generated 62 63 Public address of the key: 0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB 64 Path of the secret key file: geth-data/keystore/UTC--2024-09-29T14-49-31.655272000Z--33a904ad57d0e2cb8ffe347d3c0e83c2e875e7db 65 66 - You can share your public address with anyone. Others need it to interact with you. 67 - You must NEVER share the secret key with anyone! The key controls access to your funds! 68 - You must BACKUP your key file! Without the key, it's impossible to access account funds! 69 - You must REMEMBER your password! Without the password, it's impossible to decrypt the key! 70 ``` 71 72 In this example, the public address of the signer account is 73 `0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB`. 74 Yours will print a different address. Save it for later usage. 75 76 Next set an environment variable for later usage: 77 78 ```bash 79 export GETH_SIGNER_ADDR="0x0000000000000000000000000000000000000000" 80 echo ${GETH_SIGNER_ADDR} > geth_signer_address.txt 81 ``` 82 83 > Here make sure you replace `0x0000000000000000000000000000000000000000` 84 > with your public address of the signer account 85 > (`0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB` in our example). 86 87 ### 1.2. Configure The Network and Create the Genesis Block 88 89 The next step is telling geth what kind of network you want to run. 90 We will be running a [pre-merge](https://ethereum.org/en/roadmap/merge/) 91 network with Proof-of-Authority consensus. 92 To get that working, create a `network.json` file. 93 94 If you set the `GETH_SIGNER_ADDR` variable above you can run the following 95 command to create the `network.json` file: 96 97 ```bash 98 echo "{\"config\": { \"chainId\": 12345, \"homesteadBlock\": 0, \"eip150Block\": 0, \"eip155Block\": 0, \"eip158Block\": 0, \"byzantiumBlock\": 0, \"constantinopleBlock\": 0, \"petersburgBlock\": 0, \"istanbulBlock\": 0, \"berlinBlock\": 0, \"londonBlock\": 0, \"arrowGlacierBlock\": 0, \"grayGlacierBlock\": 0, \"clique\": { \"period\": 1, \"epoch\": 30000 } }, \"difficulty\": \"1\", \"gasLimit\": \"8000000\", \"extradata\": \"0x0000000000000000000000000000000000000000000000000000000000000000${GETH_SIGNER_ADDR:2}0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\", \"alloc\": { \"${GETH_SIGNER_ADDR}\": { \"balance\": \"10000000000000000000000\"}}}" > network.json 99 ``` 100 101 You can also manually create the file remembering update it with your 102 signer public address: 103 104 ```json 105 { 106 "config": { 107 "chainId": 12345, 108 "homesteadBlock": 0, 109 "eip150Block": 0, 110 "eip155Block": 0, 111 "eip158Block": 0, 112 "byzantiumBlock": 0, 113 "constantinopleBlock": 0, 114 "petersburgBlock": 0, 115 "istanbulBlock": 0, 116 "berlinBlock": 0, 117 "londonBlock": 0, 118 "arrowGlacierBlock": 0, 119 "grayGlacierBlock": 0, 120 "clique": { 121 "period": 1, 122 "epoch": 30000 123 } 124 }, 125 "difficulty": "1", 126 "gasLimit": "8000000", 127 "extradata": "0x000000000000000000000000000000000000000000000000000000000000000033A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 128 "alloc": { 129 "0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB": { 130 "balance": "10000000000000000000000" 131 } 132 } 133 } 134 ``` 135 136 Note that the signer account address is embedded in two different places: 137 * inside of the `"extradata"` string, surrounded by zeroes and stripped of 138 its `0x` prefix; 139 * as an entry key in the `alloc` session. 140 Make sure to replace that ID with the account ID that you wrote down in 141 [Step 1.1](#_1-1-create-a-signer-account). 142 143 Once `network.json` is created, you can initialize the network with: 144 145 ```bash 146 geth init --datadir geth-data network.json 147 ``` 148 149 The output of the above command you may include some warnings, like: 150 151 ```bash 152 WARN [08-21|14:48:12.305] Unknown config environment variable envvar=GETH_SIGNER_ADDR 153 ``` 154 155 or even errors when running the command for the first time: 156 157 ```bash 158 ERROR[08-21|14:48:12.399] Head block is not reachable 159 ``` 160 161 The important part is that at the end you should see something similar to: 162 163 ```bash 164 INFO [08-21|14:48:12.639] Successfully wrote genesis state database=lightchaindata hash=768bf1..42d06a 165 ``` 166 167 ### 1.3. Start your PoA Node 168 169 We are now ready to start our $1$-node, private blockchain. 170 To launch the signer node, open a separate terminal in the same working 171 directory and make sure you have the `GETH_SIGNER_ADDR` set. 172 For convenience use the `geth_signer_address.txt`: 173 174 ```bash 175 export GETH_SIGNER_ADDR=$(cat geth_signer_address.txt) 176 ``` 177 178 Having the `GETH_SIGNER_ADDR` variable set, run: 179 180 ```bash 181 geth\ 182 --datadir geth-data\ 183 --networkid 12345\ 184 --unlock ${GETH_SIGNER_ADDR}\ 185 --nat extip:127.0.0.1\ 186 --netrestrict 127.0.0.0/24\ 187 --mine\ 188 --miner.etherbase ${GETH_SIGNER_ADDR}\ 189 --http\ 190 --allow-insecure-unlock 191 ``` 192 193 Note that, once again, the signer account created in 194 [Step 1.1](#_1-1-create-a-signer-account) appears both in 195 `--unlock` and `--allow-insecure-unlock`. 196 197 Geth will prompt you to insert the account's password as it starts up. 198 Once you do that, it should be able to start up and begin "mining" blocks. 199 200 Also here, you may encounter errors like: 201 202 ```bash 203 ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=c845e51a5e470e44 ip=18.138.108.67 204 ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=f23ac6da7c02f84a ip=3.209.45.79 205 ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=ef2d7ab886910dc8 ip=65.108.70.101 206 ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=6b36f791352f15eb ip=157.90.35.166 207 ``` 208 209 You can safely ignore them. 210 211 If the command above fails with: 212 213 ```bash 214 Fatal: Failed to register the Ethereum service: only PoS networks are supported, please transition old ones with Geth v1.13.x 215 ``` 216 217 make sure, you are running the correct Geth version 218 (see Section [Prerequisites](#prerequisites)) 219 220 ## 2. Set Up The Marketplace 221 222 You will need to open new terminal for this section and geth needs to be 223 running already. Setting up the Codex marketplace entails: 224 225 1. Deploying the Codex Marketplace contracts to our private blockchain 226 2. Setup Ethereum accounts we will use to buy and sell storage in 227 the Codex marketplace 228 3. Provisioning those accounts with the required token balances 229 230 ### 2.1. Deploy the Codex Marketplace Contracts 231 232 Make sure you leave the `marketplace-tutorial` directory, and clone 233 the `codex-storage/nim-codex.git`: 234 235 ```bash 236 git clone https://github.com/codex-storage/nim-codex.git 237 ``` 238 239 > If you just want to clone the repo to run the tutorial, you can 240 > skip the history and just download the head of the master branch by using 241 > `--depth 1` option: `git clone --depth 1 https://github.com/codex-storage/nim-codex.git` 242 243 Thus, our directory structure for the purpose of this tutorial looks like this: 244 245 ```bash 246 | 247 |-- nim-codex 248 └-- marketplace-tutorial 249 ``` 250 251 > You could clone the `codex-storage/nim-codex.git` to some other location. 252 > Just to keeps things nicely separated it is best to make sure that 253 > `nim-codex` is not under `marketplace-tutorial` directory. 254 255 Now, from the `nim-codex` folder run: 256 257 ```bash 258 make update && make 259 ``` 260 261 > This may take a moment as it will also build the `nim` compiler. Be patient. 262 263 Now, in order to start a local Ethereum network run: 264 265 ```bash 266 cd vendor/codex-contracts-eth 267 npm install 268 ``` 269 270 > While writing the document we used `node` version `v20.17.0` and 271 > `npm` version `10.8.2`. 272 273 Before continuing you now must **wait until $256$ blocks are mined** 274 **in your PoAnetwork**, or deploy will fail. This should take about 275 $4$ minutes and $30$ seconds. You can check which block height you are 276 currently at by running the following command 277 **from the `marketplace-tutorial` folder**: 278 279 ```bash 280 geth attach --exec web3.eth.blockNumber ./geth-data/geth.ipc 281 ``` 282 283 once that gets past $256$, you are ready to go. 284 285 To deploy contracts, from the `codex-contracts-eth` directory run: 286 287 ```bash 288 export DISTTEST_NETWORK_URL=http://localhost:8545 289 npx hardhat --network codexdisttestnetwork deploy 290 ``` 291 292 If the command completes successfully, you will see the output similar 293 to this one: 294 295 ```bash 296 Deployed Marketplace with Groth16 Verifier at: 297 0xCf0df6C52B02201F78E8490B6D6fFf5A82fC7BCd 298 ``` 299 > of course your address will be different. 300 301 You are now ready to prepare the accounts. 302 303 ### 2.2. Generate the Required Accounts 304 305 We will run $2$ Codex nodes: a **storage provider**, which will sell storage 306 on the network, and a **client**, which will buy and use such storage; 307 we therefore need two valid Ethereum accounts. We could create random 308 accounts by using one of the many tools available to that end but, since 309 this is a tutorial running on a local private network, we will simply 310 provide you with two pre-made accounts along with their private keys, 311 which you can copy and paste instead: 312 313 First make sure you're back in the `marketplace-tutorial` folder and 314 not the `codex-contracts-eth` subfolder. Then set these variables: 315 316 **Storage:** 317 ```bash 318 export ETH_STORAGE_ADDR=0x45BC5ca0fbdD9F920Edd12B90908448C30F32a37 319 export ETH_STORAGE_PK=0x06c7ac11d4ee1d0ccb53811b71802fa92d40a5a174afad9f2cb44f93498322c3 320 echo $ETH_STORAGE_PK > storage.pkey && chmod 0600 storage.pkey 321 ``` 322 323 **Client:** 324 ```bash 325 export ETH_CLIENT_ADDR=0x9F0C62Fe60b22301751d6cDe1175526b9280b965 326 export ETH_CLIENT_PK=0x5538ec03c956cb9d0bee02a25b600b0225f1347da4071d0fd70c521fdc63c2fc 327 echo $ETH_CLIENT_PK > client.pkey && chmod 0600 client.pkey 328 ``` 329 330 ### 2.3. Provision Accounts with Tokens 331 332 We now need to transfer some ETH to each of the accounts, as well as provide 333 them with some Codex tokens for the storage node to use as collateral and 334 for the client node to buy actual storage. 335 336 Although the process is not particularly complicated, I suggest you use 337 [the script we prepared](https://github.com/gmega/local-codex-bare/blob/main/scripts/mint-tokens.js) 338 for that. This script, essentially: 339 340 1. reads the Marketplace contract address and its ABI from the deployment data; 341 2. transfers $1$ ETH from the signer account to a target account if the target 342 account has no ETH balance; 343 3. mints $n$ Codex tokens and adds it into the target account's balance. 344 345 To use the script, just download it into a local file named `mint-tokens.js`, 346 for instance using `curl` (make sure you are in 347 the `marketplace-tutorial` directory): 348 349 ```bash 350 # download script 351 curl https://raw.githubusercontent.com/gmega/codex-local-bare/main/scripts/mint-tokens.js -o mint-tokens.js 352 ``` 353 354 Then run: 355 356 ```bash 357 # set the contract file location (we assume you are in the marketplace-tutorial directory) 358 export CONTRACT_DEPLOY_FULL="../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork" 359 export GETH_SIGNER_ADDR=$(cat geth_signer_address.txt) 360 # Installs Web3-js 361 npm install web3 362 # Provides tokens to the storage account. 363 node ./mint-tokens.js $CONTRACT_DEPLOY_FULL/TestToken.json $GETH_SIGNER_ADDR 0x45BC5ca0fbdD9F920Edd12B90908448C30F32a37 10000000000 364 # Provides tokens to the client account. 365 node ./mint-tokens.js $CONTRACT_DEPLOY_FULL/TestToken.json $GETH_SIGNER_ADDR 0x9F0C62Fe60b22301751d6cDe1175526b9280b965 10000000000 366 ``` 367 368 If you get a message like 369 370 ```bash 371 Usage: mint-tokens.js <token-hardhat-deploy-json> <signer-account> <receiver-account> <token-ammount> 372 ``` 373 374 then you need to ensure you provided all the required arguments. 375 In particular you need to ensure that the `GETH_SIGNER_ADDR` env variable 376 holds the signer address (we used 377 `export GETH_SIGNER_ADDR=$(cat geth_signer_address.txt)` above to 378 make sure it is set). 379 380 ## 3. Run Codex 381 382 With accounts and geth in place, we can now start the Codex nodes. 383 384 ### 3.1. Storage Node 385 386 The storage node will be the one storing data and submitting the proofs of 387 storage to the chain. To do that, it needs access to: 388 389 1. the address of the Marketplace contract that has been deployed to 390 the local geth node in [Step 2.1](#_2-1-deploy-the-codex-marketplace-contracts); 391 2. the sample ceremony files which are shipped in the Codex contracts repo 392 (`nim-codex/vendor/codex-contracts-eth`). 393 394 **Address of the Marketplace Contract.** The contract address can be found 395 inside of the file `nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork/Marketplace.json`. 396 We captured that location above in `CONTRACT_DEPLOY_FULL` variable, thus, from 397 the `marketplace-tutorial` folder just run: 398 399 ```bash 400 grep '"address":' ${CONTRACT_DEPLOY_FULL}/Marketplace.json 401 ``` 402 403 which should print something like: 404 ```bash 405 "address": "0xCf0df6C52B02201F78E8490B6D6fFf5A82fC7BCd", 406 ``` 407 408 > This address should match the address we got earlier when deploying 409 > the Marketplace contract above. 410 411 Then run the following with the correct market place address: 412 ```bash 413 export MARKETPLACE_ADDRESS="0x0000000000000000000000000000000000000000" 414 echo ${MARKETPLACE_ADDRESS} > marketplace_address.txt 415 ``` 416 417 where you replace `0x0000000000000000000000000000000000000000` with 418 the Marketplace contract above in 419 [Step 2.1](#_2-1-deploy-the-codex-marketplace-contracts). 420 421 **Prover ceremony files.** The ceremony files are under the 422 `nim-codex/vendor/codex-contracts-eth/verifier/networks/codexdisttestnetwork` 423 subdirectory. There are three of them: `proof_main.r1cs`, `proof_main.zkey`, 424 and `prooof_main.wasm`. We will need all of them to start the Codex storage node. 425 426 **Starting the storage node.** Let: 427 428 * `PROVER_ASSETS` contain the directory where the prover ceremony files are 429 located. **This must be an absolute path**; 430 * `CODEX_BINARY` contain the location of your Codex binary; 431 * `MARKETPLACE_ADDRESS` contain the address of the Marketplace contract 432 (we have already set it above). 433 434 Set these paths into environment variables (make sure you are in 435 the `marketplace-tutorial` directory): 436 437 ```bash 438 export CONTRACT_DEPLOY_FULL=$(realpath "../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork") 439 export PROVER_ASSETS=$(realpath "../nim-codex/vendor/codex-contracts-eth/verifier/networks/codexdisttestnetwork/") 440 export CODEX_BINARY=$(realpath "../nim-codex/build/codex") 441 export MARKETPLACE_ADDRESS=$(cat marketplace_address.txt) 442 ``` 443 > you may notice, that we have already set the `CONTRACT_DEPLOY_FULL` variable 444 > above. Here, we make sure it is an absolute path. 445 446 To launch the storage node, run: 447 448 ```bash 449 ${CODEX_BINARY}\ 450 --data-dir=./codex-storage\ 451 --listen-addrs=/ip4/0.0.0.0/tcp/8080\ 452 --api-port=8000\ 453 --disc-port=8090\ 454 persistence\ 455 --eth-provider=http://localhost:8545\ 456 --eth-private-key=./storage.pkey\ 457 --marketplace-address=${MARKETPLACE_ADDRESS}\ 458 --validator\ 459 --validator-max-slots=1000\ 460 prover\ 461 --circom-r1cs=${PROVER_ASSETS}/proof_main.r1cs\ 462 --circom-wasm=${PROVER_ASSETS}/proof_main.wasm\ 463 --circom-zkey=${PROVER_ASSETS}/proof_main.zkey 464 ``` 465 466 **Starting the client node.** 467 468 The client node is started similarly except that: 469 470 * we need to pass the SPR of the storage node so it can form a network with it; 471 * since it does not run any proofs, it does not require any ceremony files. 472 473 We get the Signed Peer Record (SPR) of the storage node so we can bootstrap 474 the client node with it. To get the SPR, issue the following call: 475 476 ```bash 477 curl -H 'Accept: text/plain' 'http://localhost:8000/api/codex/v1/spr' --write-out '\n' 478 ``` 479 480 You should get the SPR back starting with `spr:`. 481 482 Before you proceed, open new terminal, and enter `marketplace-tutorial` directory. 483 484 Next set these paths into environment variables: 485 486 ```bash 487 # set the SPR for the storage node 488 export STORAGE_NODE_SPR=$(curl -H 'Accept: text/plain' 'http://localhost:8000/api/codex/v1/spr') 489 # basic vars 490 export CONTRACT_DEPLOY_FULL=$(realpath "../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork") 491 export CODEX_BINARY=$(realpath "../nim-codex/build/codex") 492 export MARKETPLACE_ADDRESS=$(cat marketplace_address.txt) 493 ``` 494 and then run: 495 496 ```bash 497 ${CODEX_BINARY}\ 498 --data-dir=./codex-client\ 499 --listen-addrs=/ip4/0.0.0.0/tcp/8081\ 500 --api-port=8001\ 501 --disc-port=8091\ 502 --bootstrap-node=${STORAGE_NODE_SPR}\ 503 persistence\ 504 --eth-provider=http://localhost:8545\ 505 --eth-private-key=./client.pkey\ 506 --marketplace-address=${MARKETPLACE_ADDRESS} 507 ``` 508 509 ## 4. Buy and Sell Storage on the Marketplace 510 511 Any storage negotiation has two sides: a buyer and a seller. 512 Therefore, before we can actually request storage, we must first offer 513 some of it for sale. 514 515 ### 4.1 Sell Storage 516 517 The following request will cause the storage node to put out $50\text{MB}$ 518 of storage for sale for $1$ hour, at a price of $1$ Codex token 519 per slot per second, while expressing that it's willing to take at most 520 a $1000$ Codex token penalty for not fulfilling its part of the contract.[^1] 521 522 ```bash 523 curl 'http://localhost:8000/api/codex/v1/sales/availability' \ 524 --header 'Content-Type: application/json' \ 525 --data '{ 526 "totalSize": "50000000", 527 "duration": "3600", 528 "minPrice": "1", 529 "maxCollateral": "1000" 530 }' 531 ``` 532 533 This should return a JSON response containing an `id` (e.g. `"id": "0xb55b3bc7aac2563d5bf08ce8a177a38b5a40254bfa7ee8f9c52debbb176d44b0"`) 534 which identifies this storage offer. 535 536 > To make JSON responses more readable, you can try 537 > [jq](https://jqlang.github.io/jq/) JSON formatting utility 538 > by just adding `| jq` after the command. 539 > On macOS you can install with `brew install jq`. 540 541 To check the current storage offers for this node, you can issue: 542 543 ```bash 544 curl 'http://localhost:8000/api/codex/v1/sales/availability' 545 ``` 546 547 or with `jq`: 548 549 ```bash 550 curl 'http://localhost:8000/api/codex/v1/sales/availability' | jq 551 ``` 552 553 This should print a list of offers, with the one you just created figuring 554 among them (for our tutorial, there will be only one offer returned 555 at this time). 556 557 ### 4.2. Buy Storage 558 559 Before we can buy storage, we must have some actual data to request 560 storage for. Start by uploading a small file to your client node. 561 On Linux (or macOS) you could, for instance, use `dd` to generate a $1M$ file: 562 563 ```bash 564 dd if=/dev/urandom of=./data.bin bs=1M count=1 565 ``` 566 567 Assuming your file is named `data.bin`, you can upload it with: 568 569 ```bash 570 curl --request POST http://localhost:8001/api/codex/v1/data --header 'Content-Type: application/octet-stream' --write-out '\n' -T ./data.bin 571 ``` 572 573 Once the upload completes, you should see a _Content Identifier_, 574 or _CID_ (e.g. `zDvZRwzm2mK7tvDzKScRLapqGdgNTLyyEBvx1TQY37J2CdWdS6Sj`) 575 for the uploaded file printed to the terminal. 576 Use that CID in the purchase request: 577 578 ```bash 579 # make sure to replace the CID before with the CID you got in the previous step 580 export CID=zDvZRwzm2mK7tvDzKScRLapqGdgNTLyyEBvx1TQY37J2CdWdS6Sj 581 ``` 582 583 ```bash 584 curl "http://localhost:8001/api/codex/v1/storage/request/${CID}" \ 585 --header 'Content-Type: application/octet-stream' \ 586 --data "{ 587 \"duration\": \"600\", 588 \"reward\": \"1\", 589 \"proofProbability\": \"3\", 590 \"expiry\": \"500\", 591 \"nodes\": 3, 592 \"tolerance\": 1, 593 \"collateral\": \"1000\" 594 }" \ 595 --write-out '\n' 596 ``` 597 598 The parameters under `--data` say that: 599 600 1. we want to purchase storage for our file for $5$ minutes (`"duration": "600"`); 601 2. we are willing to pay up to $1$ token per slot per second (`"reward": "1"`) 602 3. our file will be split into three pieces (`"nodes": 3`). 603 Because we set `"tolerance": 1` we only need two (`nodes - tolerance`) 604 pieces to rebuild the file; i.e., we can tolerate that at most one node 605 stops storing our data; either due to failure or other reasons; 606 4. we demand `1000` tokens in collateral from storage providers for each piece. 607 Since there are $3$ such pieces, there will be `3000` in total collateral 608 committed by the storage provider(s) once our request is started. 609 5. finally, the `expiry` puts a time limit for filling all the slots by 610 the storage provider(s). If slot are not filled by the `expire` interval, 611 the request will timeout and fail. 612 613 ### 4.3. Track your Storage Requests 614 615 POSTing a storage request will make it available in the storage market, 616 and a storage node will eventually pick it up. 617 618 You can poll the status of your request by means of: 619 ```bash 620 export STORAGE_PURCHASE_ID="1d0ec5261e3364f8b9d1cf70324d70af21a9b5dccba380b24eb68b4762249185" 621 curl "http://localhost:8001/api/codex/v1/storage/purchases/${STORAGE_PURCHASE_ID}" 622 ``` 623 624 For instance: 625 626 ```bash 627 > curl 'http://localhost:8001/api/codex/v1/storage/purchases/6c698cd0ad71c41982f83097d6fa75beb582924e08a658357a1cd4d7a2a6766d' 628 ``` 629 630 This returns a result like: 631 632 ```json 633 { 634 "requestId": "0x86501e4677a728c6a8031971d09b921c3baa268af06b9f17f1b745e7dba5d330", 635 "request": { 636 "client": "0x9f0c62fe60b22301751d6cde1175526b9280b965", 637 "ask": { 638 "slots": 3, 639 "slotSize": "262144", 640 "duration": "1000", 641 "proofProbability": "3", 642 "reward": "1", 643 "collateral": "1", 644 "maxSlotLoss": 1 645 }, 646 "content": { 647 "cid": "zDvZRwzkyw1E7ABaUSmgtNEDjC7opzhUoHo99Vpvc98cDWeCs47u" 648 }, 649 "expiry": "1711992852", 650 "nonce": "0x9f5e651ecd3bf73c914f8ed0b1088869c64095c0d7bd50a38fc92ebf66ff5915", 651 "id": "0x6c698cd0ad71c41982f83097d6fa75beb582924e08a658357a1cd4d7a2a6766d" 652 }, 653 "state": "submitted", 654 "error": null 655 } 656 ``` 657 658 Shows that a request has been submitted but has not yet been filled. 659 Your request will be successful once `"state"` shows `"started"`. 660 Anything other than that means the request has not been completely 661 processed yet, and an `"error"` state other than `null` means it failed. 662 663 Well, it was quite a journey, wasn't it? You can congratulate yourself for 664 successfully finishing the codex marketplace tutorial! 665 666 [^1]: Codex files get partitioned into pieces called "slots" and distributed 667 to various storage providers. The collateral refers to one such slot, 668 and will be slowly eaten away as the storage provider fails to deliver 669 timely proofs, but the actual logic is [more involved than that](https://github.com/codex-storage/codex-contracts-eth/blob/6c9f797f408608958714024b9055fcc330e3842f/contracts/Marketplace.sol#L209).