mirror of
https://github.com/logos-storage/logos-storage-docs.git
synced 2026-02-07 22:53:12 +00:00
663 lines
34 KiB
Markdown
663 lines
34 KiB
Markdown
---
|
||
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).
|