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 `11.0.0`. 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 1000000000000000000 364 # Provides tokens to the client account. 365 node ./mint-tokens.js $CONTRACT_DEPLOY_FULL/TestToken.json $GETH_SIGNER_ADDR 0x9F0C62Fe60b22301751d6cDe1175526b9280b965 1000000000000000000 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 address of the Marketplace contract. 419 420 **Prover ceremony files.** The ceremony files are under the 421 `nim-codex/vendor/codex-contracts-eth/verifier/networks/codexdisttestnetwork` 422 subdirectory. There are three of them: `proof_main.r1cs`, `proof_main.zkey`, 423 and `prooof_main.wasm`. We will need all of them to start the Codex storage node. 424 425 **Starting the storage node.** Let: 426 427 * `PROVER_ASSETS` contain the directory where the prover ceremony files are 428 located. **This must be an absolute path**; 429 * `CODEX_BINARY` contain the location of your Codex binary; 430 * `MARKETPLACE_ADDRESS` contain the address of the Marketplace contract 431 (we have already set it above). 432 433 Set these paths into environment variables (make sure you are in 434 the `marketplace-tutorial` directory): 435 436 ```bash 437 export CONTRACT_DEPLOY_FULL=$(realpath "../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork") 438 export PROVER_ASSETS=$(realpath "../nim-codex/vendor/codex-contracts-eth/verifier/networks/codexdisttestnetwork/") 439 export CODEX_BINARY=$(realpath "../nim-codex/build/codex") 440 export MARKETPLACE_ADDRESS=$(cat marketplace_address.txt) 441 ``` 442 > you may notice, that we have already set the `CONTRACT_DEPLOY_FULL` variable 443 > above. Here, we make sure it is an absolute path. 444 445 To launch the storage node, run: 446 447 ```bash 448 ${CODEX_BINARY}\ 449 --data-dir=./codex-storage\ 450 --listen-addrs=/ip4/0.0.0.0/tcp/8080\ 451 --api-port=8000\ 452 --disc-port=8090\ 453 persistence\ 454 --eth-provider=http://localhost:8545\ 455 --eth-private-key=./storage.pkey\ 456 --marketplace-address=${MARKETPLACE_ADDRESS}\ 457 --validator\ 458 --validator-max-slots=1000\ 459 prover\ 460 --circom-r1cs=${PROVER_ASSETS}/proof_main.r1cs\ 461 --circom-wasm=${PROVER_ASSETS}/proof_main.wasm\ 462 --circom-zkey=${PROVER_ASSETS}/proof_main.zkey 463 ``` 464 465 **Starting the client node.** 466 467 The client node is started similarly except that: 468 469 * we need to pass the SPR of the storage node so it can form a network with it; 470 * since it does not run any proofs, it does not require any ceremony files. 471 472 We get the Signed Peer Record (SPR) of the storage node so we can bootstrap 473 the client node with it. To get the SPR, issue the following call: 474 475 ```bash 476 curl -H 'Accept: text/plain' 'http://localhost:8000/api/codex/v1/spr' --write-out '\n' 477 ``` 478 479 You should get the SPR back starting with `spr:`. 480 481 Before you proceed, open new terminal, and enter `marketplace-tutorial` directory. 482 483 Next set these paths into environment variables: 484 485 ```bash 486 # set the SPR for the storage node 487 export STORAGE_NODE_SPR=$(curl -H 'Accept: text/plain' 'http://localhost:8000/api/codex/v1/spr') 488 # basic vars 489 export CONTRACT_DEPLOY_FULL=$(realpath "../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork") 490 export CODEX_BINARY=$(realpath "../nim-codex/build/codex") 491 export MARKETPLACE_ADDRESS=$(cat marketplace_address.txt) 492 ``` 493 and then run: 494 495 ```bash 496 ${CODEX_BINARY}\ 497 --data-dir=./codex-client\ 498 --listen-addrs=/ip4/0.0.0.0/tcp/8081\ 499 --api-port=8001\ 500 --disc-port=8091\ 501 --bootstrap-node=${STORAGE_NODE_SPR}\ 502 persistence\ 503 --eth-provider=http://localhost:8545\ 504 --eth-private-key=./client.pkey\ 505 --marketplace-address=${MARKETPLACE_ADDRESS} 506 ``` 507 508 ## 4. Buy and Sell Storage on the Marketplace 509 510 Any storage negotiation has two sides: a buyer and a seller. 511 Therefore, before we can actually request storage, we must first offer 512 some of it for sale. 513 514 ### 4.1 Sell Storage 515 516 The following request will cause the storage node to put out $5\text{MB}$ 517 of storage for sale for $1$ hour, at a minimum price of $1000$ Codex token 518 per byte per second, while expressing that maximum penalty (a collateral) 519 the storage provider is willing to risk for not fulfilling its part of the 520 contract is limited to $50000000$ tokens (wei) for this specific availability.[^1] 521 This total collateral will be distributed across all storage requests matching 522 this availability. 523 524 ```bash 525 curl 'http://localhost:8000/api/codex/v1/sales/availability' \ 526 --header 'Content-Type: application/json' \ 527 --data '{ 528 "totalSize": "5000000", 529 "duration": "3600", 530 "minPricePerBytePerSecond": "1000", 531 "totalCollateral": "50000000" 532 }' 533 ``` 534 535 This should return a JSON response containing an `id` (e.g. 536 `"id": "0xb55b3bc7aac2563d5bf08ce8a177a38b5a40254bfa7ee8f9c52debbb176d44b0"`) 537 which identifies this storage offer. 538 539 > To make JSON responses more readable, you can try 540 > [jq](https://jqlang.github.io/jq/) JSON formatting utility 541 > by just adding `| jq` after the command. 542 > On macOS you can install with `brew install jq`. 543 544 To check the current storage offers for this node, you can issue: 545 546 ```bash 547 curl 'http://localhost:8000/api/codex/v1/sales/availability' 548 ``` 549 550 or with `jq`: 551 552 ```bash 553 curl 'http://localhost:8000/api/codex/v1/sales/availability' | jq 554 ``` 555 556 This should print a list of offers, with the one you just created figuring 557 among them (for our tutorial, there will be only one offer returned 558 at this time). 559 560 ### 4.2. Buy Storage 561 562 Before we can buy storage, we must have some actual data to request 563 storage for. Start by uploading a small file to your client node. 564 On Linux (or macOS) you could, for instance, use `dd` to generate a $1M$ file: 565 566 ```bash 567 dd if=/dev/urandom of=./data.bin bs=1M count=1 568 ``` 569 570 Assuming your file is named `data.bin`, you can upload it with: 571 572 ```bash 573 curl --request POST http://localhost:8001/api/codex/v1/data --header 'Content-Type: application/octet-stream' --write-out '\n' -T ./data.bin 574 ``` 575 576 Once the upload completes, you should see a _Content Identifier_, 577 or _CID_ (e.g. `zDvZRwzm2mK7tvDzKScRLapqGdgNTLyyEBvx1TQY37J2CdWdS6Sj`) 578 for the uploaded file printed to the terminal. 579 Use that CID in the purchase request: 580 581 ```bash 582 # make sure to replace the CID before with the CID you got in the previous step 583 export CID=zDvZRwzm2mK7tvDzKScRLapqGdgNTLyyEBvx1TQY37J2CdWdS6Sj 584 ``` 585 586 ```bash 587 curl "http://localhost:8001/api/codex/v1/storage/request/${CID}" \ 588 --header 'Content-Type: application/octet-stream' \ 589 --data "{ 590 \"duration\": \"600\", 591 \"pricePerBytePerSecond\": \"2000\", 592 \"proofProbability\": \"3\", 593 \"expiry\": \"500\", 594 \"nodes\": 3, 595 \"tolerance\": 1, 596 \"collateralPerByte\": \"1\" 597 }" \ 598 --write-out '\n' 599 ``` 600 601 The parameters under `--data` say that: 602 603 1. we want to purchase storage for our file for $5$ minutes (`"duration": "600"`); 604 2. we are willing to pay up to $2000$ tokens (wei) per slot per second 605 (`"pricePerBytePerSecond": "2000"`). It is then twice as much as 606 `minPricePerBytePerSecond`, which we set to $1000$ when creating the availability 607 above. 608 3. our file will be split into three pieces (`"nodes": 3`). 609 Because we set `"tolerance": 1` we only need two (`nodes - tolerance`) 610 pieces to rebuild the file; i.e., we can tolerate that at most one node 611 stops storing our data; either due to failure or other reasons; 612 4. we demand `1` token in collateral from storage providers per byte of storage 613 per second for each piece of data (called _slots_). Because we provide some redundancy to 614 the stored data, the actual size of the stored dataset will be bigger than original 615 content (the bigger the `tolerance` the bigger the resulting dataset). 616 5. finally, the `expiry` puts a time limit for filling all the slots by 617 the storage provider(s). If slots are not filled by the `expire` interval, 618 the request will timeout and fail. 619 620 ### 4.3. Track your Storage Requests 621 622 POSTing a storage request will make it available in the storage market, 623 and a storage node will eventually pick it up. 624 625 You can poll the status of your request by means of: 626 ```bash 627 export STORAGE_PURCHASE_ID="6b6e2445f33ed624891f0543fe9dbf4bd0a6971febccaae2431375a5b9a2840d" 628 curl "http://localhost:8001/api/codex/v1/storage/purchases/${STORAGE_PURCHASE_ID}" 629 ``` 630 631 This returns a result like: 632 633 ```json 634 { 635 "requestId": "0x6b6e2445f33ed624891f0543fe9dbf4bd0a6971febccaae2431375a5b9a2840d", 636 "request": { 637 "client": "0x9f0c62fe60b22301751d6cde1175526b9280b965", 638 "ask": { 639 "proofProbability": "3", 640 "pricePerBytePerSecond": "2000", 641 "collateralPerByte": "1", 642 "slots": 3, 643 "slotSize": 524288, 644 "duration": 600, 645 "maxSlotLoss": 1 646 }, 647 "content": { 648 "cid": "zDvZRwzm18zqvTRMHhjDmwybKZaomW8bDFtdSyaQ4XM6MmER5fzy" 649 }, 650 "expiry": 500, 651 "nonce": "0x5267b832fe9a978fb0dd3912b42fece7c5ac074a9cc3c74bf578b6cee9e43543", 652 "id": "0x6b6e2445f33ed624891f0543fe9dbf4bd0a6971febccaae2431375a5b9a2840d" 653 }, 654 "state": "submitted", 655 "error": null 656 } 657 ``` 658 659 Shows that a request has been submitted but has not yet been filled. 660 Your request will be successful once `"state"` shows `"started"`. 661 Anything other than that means the request has not been completely 662 processed yet, and an `"error"` state other than `null` means it failed. 663 664 Well, it was quite a journey, wasn't it? You can congratulate yourself for 665 successfully finishing the codex marketplace tutorial! 666 667 [^1]: Codex files get partitioned into pieces called "slots" and distributed 668 to various storage providers. The collateral refers to one such slot, 669 and will be slowly eaten away as the storage provider fails to deliver 670 timely proofs.