logos-storage-docs-old/ru/learn/local-marketplace.md

663 lines
34 KiB
Markdown
Raw Normal View History

---
outline: [2, 3]
---
# Запуск локальной сети Codex с поддержкой маркетплейса
Это руководство научит вас, как запустить небольшую сеть Codex с включенным
аркетплейсом хранения_; т.е. функциональностью в Codex, которая
позволяет участникам предлагать и покупать хранилище на рынке, обеспечивая
честное выполнение обязательств поставщиками хранилища с помощью криптографических доказательств.
В этом руководстве вы:
1. [Настроите сеть Geth PoA](#_1-set-up-a-geth-poa-network);
2. [Настроите маркетплейс](#_2-set-up-the-marketplace);
3. [Запустите Codex](#_3-run-codex);
4. [Купите и продайте хранилище на маркетплейсе](#_4-buy-and-sell-storage-on-the-marketplace).
## Предварительные требования
Для прохождения этого руководства вам понадобится:
* клиент Ethereum [geth](https://github.com/ethereum/go-ethereum);
Вам нужна версия `1.13.x` geth, так как более новые версии больше не поддерживают
Proof of Authority (PoA). Это руководство было протестировано с версией geth `1.13.15`.
* бинарный файл Codex, который [можно собрать из исходного кода](https://github.com/codex-storage/nim-codex?tab=readme-ov-file#build-and-run).
Мы также будем использовать синтаксис [bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell))
на протяжении всего руководства. Если вы используете другую оболочку, вам может потребоваться адаптировать
команды под вашу платформу.
Для начала создайте новую папку, где мы будем хранить файлы, связанные с руководством,
чтобы держать их отдельно от репозитория codex.
Предположим, что имя папки будет `marketplace-tutorial`.
## 1. Настройка сети Geth PoA
Для этого руководства мы будем использовать простую
[Proof-of-Authority](https://github.com/ethereum/EIPs/issues/225) сеть
с geth. Первым шагом является создание _учетной записи подписанта_: учетной записи, которая
будет использоваться geth для подписи блоков в сети.
Любой блок, подписанный подписантом, принимается как действительный.
### 1.1. Создание учетной записи подписанта
Чтобы создать учетную запись подписанта, из директории `marketplace-tutorial` выполните:
```bash
geth account new --datadir geth-data
```
Генератор учетных записей попросит вас ввести пароль, который вы можете
оставить пустым. Затем он выведет некоторую информацию,
включая публичный адрес учетной записи:
```bash
INFO [09-29|16:49:24.244] Maximum peer count ETH=50 total=50
Your new account is locked with a password. Please give a password. Do not forget this password.
Password:
Repeat password:
Your new key was generated
Public address of the key: 0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB
Path of the secret key file: geth-data/keystore/UTC--2024-09-29T14-49-31.655272000Z--33a904ad57d0e2cb8ffe347d3c0e83c2e875e7db
- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
```
В этом примере публичный адрес учетной записи подписанта -
`0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB`.
У вас будет выведен другой адрес. Сохраните его для дальнейшего использования.
Затем установите переменную окружения для дальнейшего использования:
```bash
export GETH_SIGNER_ADDR="0x0000000000000000000000000000000000000000"
echo ${GETH_SIGNER_ADDR} > geth_signer_address.txt
```
> Здесь убедитесь, что вы заменили `0x0000000000000000000000000000000000000000`
> на ваш публичный адрес учетной записи подписанта
> (`0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB` в нашем примере).
### 1.2. Настройка сети и создание генезис-блока
Следующий шаг - указать geth, какую сеть вы хотите запустить.
Мы будем запускать [pre-merge](https://ethereum.org/en/roadmap/merge/)
сеть с консенсусом Proof-of-Authority.
Чтобы это работало, создайте файл `network.json`.
Если вы установили переменную `GETH_SIGNER_ADDR` выше, вы можете выполнить следующую
команду для создания файла `network.json`:
```bash
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
```
Вы также можете создать файл вручную, не забыв обновить его своим
публичным адресом подписанта:
```json
{
"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": "0x000000000000000000000000000000000000000000000000000000000000000033A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"0x33A904Ad57D0E2CB8ffe347D3C0E83C2e875E7dB": {
"balance": "10000000000000000000000"
}
}
}
```
Обратите внимание, что адрес учетной записи подписанта встроен в два разных места:
* внутри строки `"extradata"`, окруженный нулями и без префикса `0x`;
* как ключ записи в секции `alloc`.
Убедитесь, что вы заменили этот ID на ID учетной записи, который вы записали в
[Шаге 1.1](#_1-1-create-a-signer-account).
После создания `network.json` вы можете инициализировать сеть с помощью:
```bash
geth init --datadir geth-data network.json
```
В выводе этой команды могут быть предупреждения, например:
```bash
WARN [08-21|14:48:12.305] Unknown config environment variable envvar=GETH_SIGNER_ADDR
```
или даже ошибки при первом запуске команды:
```bash
ERROR[08-21|14:48:12.399] Head block is not reachable
```
Важно, что в конце вы должны увидеть что-то похожее на:
```bash
INFO [08-21|14:48:12.639] Successfully wrote genesis state database=lightchaindata hash=768bf1..42d06a
```
### 1.3. Запуск вашего PoA узла
Теперь мы готовы запустить нашу $1$-узловую приватную блокчейн-сеть.
Чтобы запустить узел подписанта, откройте отдельный терминал в той же рабочей
директории и убедитесь, что у вас установлена переменная `GETH_SIGNER_ADDR`.
Для удобства используйте `geth_signer_address.txt`:
```bash
export GETH_SIGNER_ADDR=$(cat geth_signer_address.txt)
```
Имея установленную переменную `GETH_SIGNER_ADDR`, выполните:
```bash
geth\
--datadir geth-data\
--networkid 12345\
--unlock ${GETH_SIGNER_ADDR}\
--nat extip:127.0.0.1\
--netrestrict 127.0.0.0/24\
--mine\
--miner.etherbase ${GETH_SIGNER_ADDR}\
--http\
--allow-insecure-unlock
```
Обратите внимание, что учетная запись подписанта, созданная в
[Шаге 1.1](#_1-1-create-a-signer-account), снова появляется как в
`--unlock`, так и в `--allow-insecure-unlock`.
Geth попросит вас ввести пароль учетной записи при запуске.
После этого он должен запуститься и начать "майнить" блоки.
Здесь также могут возникнуть ошибки, например:
```bash
ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=c845e51a5e470e44 ip=18.138.108.67
ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=f23ac6da7c02f84a ip=3.209.45.79
ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=ef2d7ab886910dc8 ip=65.108.70.101
ERROR[08-21|15:00:27.625] Bootstrap node filtered by netrestrict id=6b36f791352f15eb ip=157.90.35.166
```
Их можно безопасно игнорировать.
Если команда выше завершается с ошибкой:
```bash
Fatal: Failed to register the Ethereum service: only PoS networks are supported, please transition old ones with Geth v1.13.x
```
убедитесь, что вы используете правильную версию Geth
(см. раздел [Предварительные требования](#prerequisites))
## 2. Настройка маркетплейса
Для этого раздела вам нужно открыть новый терминал, и geth должен быть уже запущен.
Настройка маркетплейса Codex включает:
1. Развертывание контрактов маркетплейса Codex в нашу приватную блокчейн-сеть
2. Настройку учетных записей Ethereum, которые мы будем использовать для покупки и продажи хранилища в
маркетплейсе Codex
3. Обеспечение этих учетных записей необходимыми балансами токенов
### 2.1. Развертывание контрактов маркетплейса Codex
Убедитесь, что вы вышли из директории `marketplace-tutorial` и клонируйте
`codex-storage/nim-codex.git`:
```bash
git clone https://github.com/codex-storage/nim-codex.git
```
> Если вы хотите просто клонировать репозиторий для прохождения руководства, вы можете
> пропустить историю и просто скачать голову ветки master, используя
> опцию `--depth 1`: `git clone --depth 1 https://github.com/codex-storage/nim-codex.git`
Таким образом, структура директорий для целей этого руководства выглядит так:
```bash
|
|-- nim-codex
└-- marketplace-tutorial
```
> Вы можете клонировать `codex-storage/nim-codex.git` в другое место.
Теперь из папки `nim-codex` выполните:
```bash
make update && make
```
> Это может занять некоторое время, так как это также соберет компилятор `nim`. Будьте терпеливы.
Теперь, чтобы запустить локальную сеть Ethereum, выполните:
```bash
cd vendor/codex-contracts-eth
npm install
```
> При написании документа мы использовали `node` версии `v20.17.0` и
> `npm` версии `10.8.2`.
Прежде чем продолжить, вы должны **дождаться, пока будет добыто $256$ блоков**
**в вашей PoA сети**, иначе развертывание завершится неудачей. Это должно занять около
$4$ минут и $30$ секунд. Вы можете проверить, на какой высоте блока вы находитесь,
выполнив следующую команду
**из папки `marketplace-tutorial`**:
```bash
geth attach --exec web3.eth.blockNumber ./geth-data/geth.ipc
```
как только это превысит $256$, вы готовы к работе.
Чтобы развернуть контракты, из директории `codex-contracts-eth` выполните:
```bash
export DISTTEST_NETWORK_URL=http://localhost:8545
npx hardhat --network codexdisttestnetwork deploy
```
Если команда завершится успешно, вы увидите вывод, похожий на этот:
```bash
Deployed Marketplace with Groth16 Verifier at:
0xCf0df6C52B02201F78E8490B6D6fFf5A82fC7BCd
```
> конечно, ваш адрес будет другим.
Теперь вы готовы подготовить учетные записи.
### 2.2. Генерация необходимых учетных записей
Мы будем запускать $2$ узла Codex: **поставщик хранилища**, который будет продавать хранилище
в сети, и **клиент**, который будет покупать и использовать такое хранилище;
поэтому нам нужны две действительные учетные записи Ethereum. Мы могли бы создать случайные
учетные записи, используя один из многих доступных инструментов, но, поскольку
это руководство работает в локальной приватной сети, мы просто предоставим вам
две предварительно созданные учетные записи вместе с их приватными ключами,
которые вы можете скопировать и вставить:
Сначала убедитесь, что вы вернулись в папку `marketplace-tutorial` и
не находитесь в подпапке `codex-contracts-eth`. Затем установите эти переменные:
**Хранилище:**
```bash
export ETH_STORAGE_ADDR=0x45BC5ca0fbdD9F920Edd12B90908448C30F32a37
export ETH_STORAGE_PK=0x06c7ac11d4ee1d0ccb53811b71802fa92d40a5a174afad9f2cb44f93498322c3
echo $ETH_STORAGE_PK > storage.pkey && chmod 0600 storage.pkey
```
**Клиент:**
```bash
export ETH_CLIENT_ADDR=0x9F0C62Fe60b22301751d6cDe1175526b9280b965
export ETH_CLIENT_PK=0x5538ec03c956cb9d0bee02a25b600b0225f1347da4071d0fd70c521fdc63c2fc
echo $ETH_CLIENT_PK > client.pkey && chmod 0600 client.pkey
```
### 2.3. Обеспечение учетных записей токенами
Теперь нам нужно перевести немного ETH на каждую из учетных записей, а также предоставить
им некоторые токены Codex для использования узлом хранилища в качестве залога и
для клиентского узла для покупки фактического хранилища.
Хотя процесс не особенно сложен, я предлагаю вам использовать
[скрипт, который мы подготовили](https://github.com/gmega/local-codex-bare/blob/main/scripts/mint-tokens.js)
для этого. Этот скрипт, по сути:
1. читает адрес контракта маркетплейса и его ABI из данных развертывания;
2. переводит $1$ ETH с учетной записи подписанта на целевую учетную запись, если целевая
учетная запись не имеет баланса ETH;
3. чеканит $n$ токенов Codex и добавляет их в баланс целевой учетной записи.
Чтобы использовать скрипт, просто скачайте его в локальный файл с именем `mint-tokens.js`,
например, используя `curl` (убедитесь, что вы находитесь в
директории `marketplace-tutorial`):
```bash
# скачать скрипт
curl https://raw.githubusercontent.com/gmega/codex-local-bare/main/scripts/mint-tokens.js -o mint-tokens.js
```
Затем выполните:
```bash
# установить расположение файла контракта (мы предполагаем, что вы находитесь в директории marketplace-tutorial)
export CONTRACT_DEPLOY_FULL="../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork"
export GETH_SIGNER_ADDR=$(cat geth_signer_address.txt)
# Устанавливает Web3-js
npm install web3
# Предоставляет токены учетной записи хранилища.
node ./mint-tokens.js $CONTRACT_DEPLOY_FULL/TestToken.json $GETH_SIGNER_ADDR 0x45BC5ca0fbdD9F920Edd12B90908448C30F32a37 10000000000
# Предоставляет токены клиентской учетной записи.
node ./mint-tokens.js $CONTRACT_DEPLOY_FULL/TestToken.json $GETH_SIGNER_ADDR 0x9F0C62Fe60b22301751d6cDe1175526b9280b965 10000000000
```
Если вы получите сообщение типа
```bash
Usage: mint-tokens.js <token-hardhat-deploy-json> <signer-account> <receiver-account> <token-ammount>
```
то вам нужно убедиться, что вы предоставили все необходимые аргументы.
В частности, вам нужно убедиться, что переменная окружения `GETH_SIGNER_ADDR`
содержит адрес подписанта (мы использовали
`export GETH_SIGNER_ADDR=$(cat geth_signer_address.txt)` выше, чтобы
убедиться, что она установлена).
## 3. Запуск Codex
С учетными записями и geth на месте, мы теперь можем запустить узлы Codex.
### 3.1. Узел хранилища
Узел хранилища будет тем, который хранит данные и отправляет доказательства
хранения в цепочку. Для этого ему нужен доступ к:
1. адресу контракта маркетплейса, который был развернут в
локальном узле geth в [Шаге 2.1](#_2-1-deploy-the-codex-marketplace-contracts);
2. образцам файлов церемонии, которые поставляются в репозитории контрактов Codex
(`nim-codex/vendor/codex-contracts-eth`).
**Адрес контракта маркетплейса.** Адрес контракта можно найти
внутри файла `nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork/Marketplace.json`.
Мы захватили это расположение выше в переменной `CONTRACT_DEPLOY_FULL`, поэтому из
папки `marketplace-tutorial` просто выполните:
```bash
grep '"address":' ${CONTRACT_DEPLOY_FULL}/Marketplace.json
```
что должно вывести что-то вроде:
```bash
"address": "0xCf0df6C52B02201F78E8490B6D6fFf5A82fC7BCd",
```
> Этот адрес должен соответствовать адресу, который мы получили ранее при развертывании
> контракта маркетплейса выше.
Затем выполните следующее с правильным адресом маркетплейса:
```bash
export MARKETPLACE_ADDRESS="0x0000000000000000000000000000000000000000"
echo ${MARKETPLACE_ADDRESS} > marketplace_address.txt
```
где вы заменяете `0x0000000000000000000000000000000000000000` на
адрес контракта маркетплейса выше в
[Шаге 2.1](#_2-1-deploy-the-codex-marketplace-contracts).
**Файлы церемонии провайдера.** Файлы церемонии находятся в подкаталоге
`nim-codex/vendor/codex-contracts-eth/verifier/networks/codexdisttestnetwork`.
Их три: `proof_main.r1cs`, `proof_main.zkey`,
и `prooof_main.wasm`. Нам понадобятся все они для запуска узла хранилища Codex.
**Запуск узла хранилища.** Пусть:
* `PROVER_ASSETS` содержит директорию, где находятся файлы церемонии провайдера.
**Это должен быть абсолютный путь**;
* `CODEX_BINARY` содержит расположение вашего бинарного файла Codex;
* `MARKETPLACE_ADDRESS` содержит адрес контракта маркетплейса
(мы уже установили его выше).
Установите эти пути в переменные окружения (убедитесь, что вы находитесь в
директории `marketplace-tutorial`):
```bash
export CONTRACT_DEPLOY_FULL=$(realpath "../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork")
export PROVER_ASSETS=$(realpath "../nim-codex/vendor/codex-contracts-eth/verifier/networks/codexdisttestnetwork/")
export CODEX_BINARY=$(realpath "../nim-codex/build/codex")
export MARKETPLACE_ADDRESS=$(cat marketplace_address.txt)
```
> вы можете заметить, что мы уже установили переменную `CONTRACT_DEPLOY_FULL`
> выше. Здесь мы убеждаемся, что это абсолютный путь.
Чтобы запустить узел хранилища, выполните:
```bash
${CODEX_BINARY}\
--data-dir=./codex-storage\
--listen-addrs=/ip4/0.0.0.0/tcp/8080\
--api-port=8000\
--disc-port=8090\
persistence\
--eth-provider=http://localhost:8545\
--eth-private-key=./storage.pkey\
--marketplace-address=${MARKETPLACE_ADDRESS}\
--validator\
--validator-max-slots=1000\
prover\
--circom-r1cs=${PROVER_ASSETS}/proof_main.r1cs\
--circom-wasm=${PROVER_ASSETS}/proof_main.wasm\
--circom-zkey=${PROVER_ASSETS}/proof_main.zkey
```
**Запуск клиентского узла.**
Клиентский узел запускается аналогично, за исключением того, что:
* нам нужно передать SPR узла хранилища, чтобы он мог сформировать сеть с ним;
* поскольку он не выполняет никаких доказательств, ему не требуются файлы церемонии.
Мы получаем Signed Peer Record (SPR) узла хранилища, чтобы мы могли загрузить
клиентский узел с ним. Чтобы получить SPR, выполните следующий вызов:
```bash
curl -H 'Accept: text/plain' 'http://localhost:8000/api/codex/v1/spr' --write-out '\n'
```
Вы должны получить SPR, начинающийся с `spr:`.
Прежде чем продолжить, откройте новый терминал и войдите в директорию `marketplace-tutorial`.
Затем установите эти пути в переменные окружения:
```bash
# установить SPR для узла хранилища
export STORAGE_NODE_SPR=$(curl -H 'Accept: text/plain' 'http://localhost:8000/api/codex/v1/spr')
# базовые переменные
export CONTRACT_DEPLOY_FULL=$(realpath "../nim-codex/vendor/codex-contracts-eth/deployments/codexdisttestnetwork")
export CODEX_BINARY=$(realpath "../nim-codex/build/codex")
export MARKETPLACE_ADDRESS=$(cat marketplace_address.txt)
```
и затем выполните:
```bash
${CODEX_BINARY}\
--data-dir=./codex-client\
--listen-addrs=/ip4/0.0.0.0/tcp/8081\
--api-port=8001\
--disc-port=8091\
--bootstrap-node=${STORAGE_NODE_SPR}\
persistence\
--eth-provider=http://localhost:8545\
```
## 4. Покупка и продажа хранилища на маркетплейсе
Любые переговоры о хранилище имеют две стороны: покупатель и продавец.
Поэтому, прежде чем мы сможем фактически запросить хранилище, мы должны сначала предложить
его на продажу.
### 4.1 Продажа хранилища
Следующий запрос заставит узел хранилища выставить $50\text{MB}$
хранилища на продажу на $1$ час по цене $1$ токен Codex
за слот в секунду, при этом выражая готовность принять максимум
$1000$ токенов Codex в качестве штрафа за невыполнение своей части контракта.[^1]
```bash
curl 'http://localhost:8000/api/codex/v1/sales/availability' \
--header 'Content-Type: application/json' \
--data '{
"totalSize": "50000000",
"duration": "3600",
"minPrice": "1",
"maxCollateral": "1000"
}'
```
Это должно вернуть JSON-ответ, содержащий `id` (например, `"id": "0xb55b3bc7aac2563d5bf08ce8a177a38b5a40254bfa7ee8f9c52debbb176d44b0"`),
который идентифицирует это предложение хранилища.
> Чтобы сделать JSON-ответы более читаемыми, вы можете попробовать
> утилиту форматирования JSON [jq](https://jqlang.github.io/jq/)
> просто добавив `| jq` после команды.
> На macOS вы можете установить с помощью `brew install jq`.
Чтобы проверить текущие предложения хранилища для этого узла, вы можете выполнить:
```bash
curl 'http://localhost:8000/api/codex/v1/sales/availability'
```
или с `jq`:
```bash
curl 'http://localhost:8000/api/codex/v1/sales/availability' | jq
```
Это должно вывести список предложений, с тем, который вы только что создали, среди
них (для нашего руководства, в это время будет возвращено только одно предложение).
### 4.2. Покупка хранилища
Прежде чем мы сможем купить хранилище, у нас должны быть некоторые фактические данные для запроса
хранилища. Начните с загрузки небольшого файла на ваш клиентский узел.
В Linux (или macOS) вы могли бы, например, использовать `dd` для генерации файла размером $1M$:
```bash
dd if=/dev/urandom of=./data.bin bs=1M count=1
```
Предполагая, что ваш файл называется `data.bin`, вы можете загрузить его с помощью:
```bash
curl --request POST http://localhost:8001/api/codex/v1/data --header 'Content-Type: application/octet-stream' --write-out '\n' -T ./data.bin
```
После завершения загрузки вы должны увидеть _Content Identifier_,
или _CID_ (например, `zDvZRwzm2mK7tvDzKScRLapqGdgNTLyyEBvx1TQY37J2CdWdS6Sj`)
для загруженного файла, выведенный в терминал.
Используйте этот CID в запросе на покупку:
```bash
# убедитесь, что заменили CID перед с CID, который вы получили на предыдущем шаге
export CID=zDvZRwzm2mK7tvDzKScRLapqGdgNTLyyEBvx1TQY37J2CdWdS6Sj
```
```bash
curl "http://localhost:8001/api/codex/v1/storage/request/${CID}" \
--header 'Content-Type: application/octet-stream' \
--data "{
\"duration\": \"600\",
\"reward\": \"1\",
\"proofProbability\": \"3\",
\"expiry\": \"500\",
\"nodes\": 3,
\"tolerance\": 1,
\"collateral\": \"1000\"
}" \
--write-out '\n'
```
Параметры под `--data` говорят, что:
1. мы хотим купить хранилище для нашего файла на $5$ минут (`"duration": "600"`);
2. мы готовы платить до $1$ токена за слот в секунду (`"reward": "1"`)
3. наш файл будет разделен на три части (`"nodes": 3`).
Поскольку мы установили `"tolerance": 1`, нам нужно только две части (`nodes - tolerance`)
для восстановления файла; т.е. мы можем допустить, что максимум один узел
перестанет хранить наши данные; либо из-за сбоя, либо по другим причинам;
4. мы требуем `1000` токенов в качестве залога от поставщиков хранилища для каждой части.
Поскольку есть $3$ такие части, всего будет `3000` залога,
зафиксированного поставщиком(ами) хранилища, как только наш запрос будет начат.
5. наконец, `expiry` устанавливает временной лимит для заполнения всех слотов
поставщиком(ами) хранилища. Если слоты не заполнены к моменту `expire`,
запрос истечет и завершится неудачей.
### 4.3. Отслеживание ваших запросов на хранилище
POST-запрос на хранилище сделает его доступным на рынке хранилища,
и узел хранилища в конечном итоге подберет его.
Вы можете опрашивать статус вашего запроса с помощью:
```bash
export STORAGE_PURCHASE_ID="1d0ec5261e3364f8b9d1cf70324d70af21a9b5dccba380b24eb68b4762249185"
curl "http://localhost:8001/api/codex/v1/storage/purchases/${STORAGE_PURCHASE_ID}"
```
Например:
```bash
> curl 'http://localhost:8001/api/codex/v1/storage/purchases/6c698cd0ad71c41982f83097d6fa75beb582924e08a658357a1cd4d7a2a6766d'
```
Это возвращает результат типа:
```json
{
"requestId": "0x86501e4677a728c6a8031971d09b921c3baa268af06b9f17f1b745e7dba5d330",
"request": {
"client": "0x9f0c62fe60b22301751d6cde1175526b9280b965",
"ask": {
"slots": 3,
"slotSize": "262144",
"duration": "1000",
"proofProbability": "3",
"reward": "1",
"collateral": "1",
"maxSlotLoss": 1
},
"content": {
"cid": "zDvZRwzkyw1E7ABaUSmgtNEDjC7opzhUoHo99Vpvc98cDWeCs47u"
},
"expiry": "1711992852",
"nonce": "0x9f5e651ecd3bf73c914f8ed0b1088869c64095c0d7bd50a38fc92ebf66ff5915",
"id": "0x6c698cd0ad71c41982f83097d6fa75beb582924e08a658357a1cd4d7a2a6766d"
},
"state": "submitted",
"error": null
}
```
Показывает, что запрос был отправлен, но еще не заполнен.
Ваш запрос будет успешным, как только `"state"` покажет `"started"`.
Все, что отличается от этого, означает, что запрос еще не полностью
обработан, а состояние `"error"` отличное от `null` означает, что он завершился неудачей.
Ну что, это было довольно долгое путешествие, не так ли? Вы можете поздравить себя с
успешным завершением руководства по маркетплейсу codex!
[^1]: Файлы Codex разделяются на части, называемые "слотами", и распределяются
по различным поставщикам хранилища. Залог относится к одному такому слоту,
и будет медленно уменьшаться по мере того, как поставщик хранилища не сможет предоставить
своевременные доказательства, но фактическая логика [более сложна, чем это](https://github.com/codex-storage/codex-contracts-eth/blob/6c9f797f408608958714024b9055fcc330e3842f/contracts/Marketplace.sol#L209).