Редактировать: 30 января 2023 г. Изменено описание комиссий для предложений на уровне данных, чтобы оно было более точным.

Прелюдия к предложениям чиа

В сфере децентрализованных финансов (DEFI) обмен монет облегчается за счет использования Automated Market Maker (AMM). Для обеспечения ликвидности AMM на основе смарт-контрактов стимулирует поставщиков ликвидности (LP) вносить токены в AMM, обеспечивая беспрепятственный обмен между токенами. Однако это также подвергает LP риску непоправимой потери. Чтобы снизить этот риск, предложение AMM уступает LP в качестве стимула для предоставления ликвидности. Эти доходы часто предоставляются в виде токенов инфляции, которые не имеют внутренней стоимости и часто используются как средство эксплуатации ничего не подозревающих инвесторов. Избыток этих токенов в конечном итоге приводит к их обесцениванию и потере стимула для LP, что приводит к отказу AMM. Эта практика вызывает этические проблемы, поскольку часто вводит в заблуждение инвесторов, которые не знают о возможном обесценивании токена, и использует менталитет «HODL» в качестве стратегии выхода для первых последователей или венчурных капиталистов.

Кроме того, вся экосистема DEFI подвержена риску потери средств из-за эксплойтов, обнаруженных хакерами в базовых смарт-контрактах. Эти эксплойты могут принимать различные формы, включая дефекты смарт-контрактов, манипулирование ценами оракулов, атаки с использованием мгновенных кредитов и другие. Процесс исправления этих уязвимостей — это постоянная битва, так как постоянно разрабатываются новые эксплойты. К сожалению, это привело к потере миллиардов долларов через эти платформы.

Сеть Chia предлагает решение вышеупомянутых уязвимостей в DEFI, устраняя необходимость в объединении огромных средств в единую точку отказа. Его система работает на одноранговой основе (P2P) без участия посредников. Пользователь, желающий купить определенный актив, создаст Файл предложения, указав сумму актива, которую он хочет приобрести, и предмет, который он предлагает взамен. Этот файл можно отправить непосредственно другому пользователю для частного обмена или отправить на рынок предложений, например https://dexie.space. Накопление нескольких предложений на рынке в конечном итоге формирует традиционную книгу заказов, но остается P2P. Средства никогда не покидают кошелек пользователя во время открытого предложения, и нет централизованного объединения средств, что сводит к минимуму риск эксплуатации и потери средств. Кроме того, эта система работает более этично, поскольку нет необходимости стимулировать LP с помощью токенов доходности, которые в конечном итоге будут сброшены на невинных инвесторов.

Обзор разработки уровня данных

Все удаленные вызовы процедур (RPC) на уровне данных доступны через порт 8562 по умолчанию, если не указано иное в файле config.yaml, расположенном в каталоге CHIA_HOME. Вы должны убедиться, что ваше приложение включает правильные SSL-сертификаты, расположенные по адресу CHIA_HOME\mainnet\config\ssl\data_layer.

Организация данных

Слой данных Chia можно рассматривать как хранилище ключей и значений, что упрощает разработку на нем с учетом нескольких ключевых соображений. Одним из важных аспектов является организация ваших данных, так как каждый экземпляр хранилища данных называется Singleton, представляющим одно хранилище ключей и значений. Однако количество синглтонов, которые можно создать, не ограничено. Кроме того, пара ключ-значение в синглтоне может хранить идентификатор другого синглтона, что позволяет создавать сложную иерархию синглтонов.

Одноэлементные эталонные шаблоны

Версионный одноэлементный шаблон

Имея синглтон управления версиями, вы можете разделить разные версии вашей структуры данных в разных подсинглетонах. При обновлении приложения вы можете просто добавить новую версию структуры данных, сохранив при этом предыдущую. Такой подход обеспечивает плавный переход для пользователей, которые, возможно, еще не обновили свое приложение. Это также позволяет вам легко переключаться между различными версиями структуры данных для целей тестирования или отладки. Пары ключ/значение в синглтоне управления версиями могут хранить идентификатор каждого вложенного синглтона, что позволяет вам получать доступ и управлять данными, хранящимися в каждой версии.

Образец ссылки на таблицу

Еще один полезный шаблон я называю эталонным шаблоном таблицы. В этом шаблоне у меня есть основной синглтон, который действует как индекс, он ссылается на другие хранилища синглетонов, которые действуют как таблицы. Каждая таблица singleton хранит коллекцию связанных данных. Это позволяет мне организовать мои данные более осмысленным и структурированным образом, облегчая взаимодействие с ними. Кроме того, это позволяет мне сохранять размер данных каждого синглтона небольшим и управляемым, что помогает оптимизировать производительность.

Кроме того, важно отметить, что эти шаблоны могут быть вложены друг в друга. Например, один из распространенных подходов состоит в том, чтобы иметь базы данных с версиями V1, V2, … V(n), каждая из которых ссылается на один элемент, который, в свою очередь, содержит набор таблиц. Это позволяет создать высокоорганизованную и гибкую систему хранения данных на уровне данных Chia.

Создание синглтона

Создать новый синглтон на уровне данных Chia можно с помощью простого вызова RPC. Ниже приведен пример команды curl для создания нового хранилища Singleton:

curl --location --request POST 'https://<node_url>:8562/create_data_store' \
--header 'Content-Type: application/json' \
--data-raw '{
     "fee": 300000000
}'

Это создаст новое хранилище Singleton на уровне данных Chia, готовое к заполнению парами ключ-значение. <node_url> следует заменить URL-адресом узла Chia, на который будет отправлен вызов RPC.

В ответ на вызов /create_data_store RPC вы получите Singleton ID. Крайне важно сохранить этот идентификатор, так как он понадобится для ссылки на хранилище Singleton при будущих взаимодействиях с уровнем данных Chia. Например, вы можете сохранить Singleton ID в переменной или базе данных для последующего использования. Этот идентификатор действует как уникальный идентификатор хранилища Singleton и необходим для любых будущих операций с данными, хранящимися в нем.

Транслируйте свой синглтон в сеть

Вызывая /add_mirror RPC, другие пользователи смогут обнаруживать и получать доступ к вашему уровню данных с разных узлов в сети, обеспечивая его высокую доступность и легкость доступа.

Вот пример cUrl:

curl --location --request POST 'https://<node_url>:8562/add_mirror' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id": "e1ae7950f2a89736fa1268273ea7d4e3fc771fb99cccce719ceed3237d93fa49",
    "urls": "http://<local_public_ip>:<http_datalayer_server_port>",
    "amount": 1,
    "fee": 300000000
}'

Поле “id” должно быть вашим одноэлементным идентификатором, поле “urls” должно быть URL-адресом, на котором размещен ваш слой данных, а “amount” — это количество монет по умолчанию, а поля “fee” определяют сумму, которую вы готовы заплатить за добавление зеркала. Данные должны быть отформатированы в формате JSON и отправлены в виде запроса POST в указанную конечную точку. В большинстве случаев это будет ваш локальный IP-адрес и порт http-сервера Datalayer.

Заполнение вашего магазина

После того, как вы получили свой идентификатор магазина Singleton, вы можете начать заполнять его данными. Уровень данных Chia предлагает два метода управления хранилищем данных: “insert” и “delete”. Чтобы обновить существующие данные, необходимо выполнить операцию “delete”, а затем операцию “insert”. Этот подход к обновлению данных можно упростить, внедрив в приложение вспомогательную утилиту, обеспечивающую более интуитивно понятный интерфейс для управления данными в хранилище Singleton. Ограничивая доступные методы манипулирования данными до “insert” и “delete”, Chia Datalayer гарантирует, что хранилище данных останется простым и понятным в использовании, обеспечивая при этом безопасную и надежную основу для данных вашего приложения.

Список изменений

Вставка данных

Чтобы вставить данные в слой данных, вам нужно создать список изменений и передать его в /batch_update RPC. Список изменений должен содержать список пар ключ/значение в шестнадцатеричном формате, которые вы хотите вставить в хранилище. Вот пример запроса curl, который вставляет данные в хранилище уровня данных:

curl --location --request POST 'https://<node_url>:8562/batch_update' \
--header 'Content-Type: application/json' \
--data-raw '{
    "changelist": [
        {
            "action": "insert",
            "key": "666f6f626172",
            "value": "53657269616c697a656444617461"
        }
    ],
    "id": "e3110c4c1af920f84dab8cfc92f02a652c5e02dd6e9194bb935f89dbf4652bec",
    "fee": 0
}'

Здесь “id” — это идентификатор магазина Singleton, “changelist” — список пар ключ/значение, которые вы хотите вставить, а “fee” — комиссия за транзакцию.

В этом примере шестнадцатеричное значение 666f6f626172 представляет собой строку “foobar”, а значение 53657269616c697a656444617461 представляет собой закодированную строку “SerializedData”.

Важно отметить, что уровень данных требует, чтобы ключи и значения были закодированы в шестнадцатеричном формате, это позволяет хранить любые данные, если они закодированы в шестнадцатеричном формате. Это могут быть двоичные данные, сериализованные данные, объекты JSON, base64, CLVM или любые другие типы данных, если они закодированы в шестнадцатеричном формате. Уровень данных не навязывает какой-либо конкретной структуры для хранимых данных.

Удаление данных

Вот пример списка изменений для удаления данных:

curl --location --request POST 'https://<node_url>:8562/batch_update' \
--header 'Content-Type: application/json' \
--data-raw '{
    "changelist": [
        {
            "action": "delete",
            "key": "666f6f626172",
        }
    ],
    "id": "e3110c4c1af920f84dab8cfc92f02a652c5e02dd6e9194bb935f89dbf4652bec",
    "fee": 0
}'

В примере значение “key” “666f6f626172” представляет строку “foobar”. вы просто меняете действие на “delete” и вам нужно указать только удаляемый ключ.

Обновление данных

Chia Datalayer не имеет собственной концепции “update” и поддерживает только операции “insert” и “delete”. Обновление абстрагируется как “delete”, а затем как «вставка».

curl --location --request POST 'https://<node_url>:8562/batch_update' \
--header 'Content-Type: application/json' \
--data-raw '{
    "changelist": [
        {
            "action": "delete",
            "key": "666f6f626172",
        },
        {
            "action": "insert",
            "key": "666f6f626172",
            "value": "53657269616c697a656444617461"
        }
    ],
    "id": "e3110c4c1af920f84dab8cfc92f02a652c5e02dd6e9194bb935f89dbf4652bec",
    "fee": 0
}'

В Chia Datalayer нет встроенной поддержки обновлений, поэтому для внесения обновлений необходимо абстрагироваться как комбинация удаления и вставки. Важно отметить, что порядок этих операций в списке изменений имеет решающее значение, поскольку уровень данных обрабатывает каждую команду в том порядке, в котором она была получена. Однако при попытке удаления несуществующего ключа произойдет ошибка, и операция не будет завершена. В результате для приложения важно отслеживать вставленные данные, если оно намеревается выполнить обновление в будущем.

Получение данных вашего магазина

Корневой хэш

«Корневой хэш» — это важнейший компонент архитектуры DataLayer, представляющий состояние хранилища в данный момент времени. Это криптографический хэш, который служит идентификатором определенного состояния хранилища, обеспечивая безопасный и эффективный способ извлечения данных, хранящихся в хранилище.

Для извлечения данных из хранилища DataLayer требуется знание текущего корневого хэша хранилища. Корневой хеш представляет состояние магазина в определенный момент времени и служит отправной точкой для доступа к полной истории магазина с момента его создания до текущего состояния. Корневой хэш также полезен для определения того, когда обновления были успешно зафиксированы в хранилище. Потому что корневой хэш служит уникальным идентификатором состояния хранилища в любой момент времени, что позволяет легко сравнивать текущее состояние с предыдущими состояниями. Если корневой хэш остался прежним, это означает, что состояние хранилища не изменилось, а если оно изменилось, вы можете получить обновленные данные, обратившись к хранилищу с новым корневым хешем. Кроме того, хранилище, в которое никогда не вставлялись данные, всегда будет иметь корневой хэш 0x0000000000000000000000000000000000000000000000000000000000000000.

Сохранив предыдущий корневой хеш в своем приложении, вы можете отслеживать изменения корневого хэша и получать любые обновления, внесенные в хранилище.

Вот пример cURL для получения последнего корневого хэша. Этот RPC получает последний корневой хэш из последнего обновления.

curl --location --request POST 'https://<node_url>:8562/get_root' \
--header 'Content-Type: application/json' \
--data-raw '{"id":"3c35da0f22454874318419d710f2521db678d544e10599bc4ed99c094e663083"}'

Вот пример получения последнего корневого хэша для многих хранилищ. Этот RPC полезен для одновременного получения последних обновлений из многих хранилищ.

curl --location --request POST 'https://<node_url>:8562/get_roots' \
--header 'Content-Type: application/json' \
--data-raw '{"ids":[
  "37af613ae4547d3061f210aaad8cf92be7ddd199a8f344a0173bd95d150210a9",
  "c7b28cbf8cf5593b3c13ac190531f7d5b20946338b913b0af538a5c55ca26423"
]}'

Наконец, вот пример получения всей корневой истории:

curl --location --request POST 'https://<node_url>:8562/get_root_history' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id": "5708a6c2a20a00414c51b70b994cce09bb36618aa4e1eab3876bb94ac641515a"
}'

Этот RPC возвращает список корневых хэшей, каждый из которых представляет уникальное состояние хранилища. Каждый корневой хеш сопровождается высотой блока, представляющей момент времени, когда было записано состояние. Эта информация позволяет получать информацию о состоянии хранилища в любой момент времени, упрощая просмотр изменений, аудит целей и построение графика изменений.

Получение ваших данных

Получив корневой хэш, вы готовы получить данные из хранилища. Вам нужны две части информации. Одноэлементный идентификатор хранилища, из которого вы хотите получить данные, и корневой хэш, который вы хотите просмотреть. RPC для этого называется /get_keys_values

curl --location --request POST 'https://<node_url>:8562/get_keys_values' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id": "7a213fda75d97f762ad10e94c92f23d2441d48fd1fbfd2d18cb54fed3738e86e",
    "root_hash": “b1d1c8cb0f0ed5a5f23891f45d2211f7fcddfeced99dc7c9f9a06a7c7a08b2df”
}'

В этом примере singleton ID — это уникальный идентификатор хранилища уровня данных. Корень — это конкретное состояние, из которого вы хотите извлечь данные. Ответом от RPC будет массив ключей/значений из вашего хранилища в шестнадцатеричном формате. Важно иметь в виду, что DataLayer — это хранилище данных без мнения, то есть он не диктует, как должны быть структурированы данные. Таким образом, приложение должно правильно интерпретировать данные и декодировать их в формат, который можно использовать в приложении.

Обзор предложений уровня данных

В то время как традиционный файл предложения Chia указывает намерение обменять актив, если предложение будет принято, предложение уровня данных позволяет обмениваться данными в форме корректировки базы данных. Если обе стороны согласны с предложенными корректировками, уровень данных выполнит изменения в обеих базах данных одновременно. Это известно как «Атомное обновление». Этот механизм обеспечивает безопасный и эффективный обмен данными без посредников. Предложение Data Layer предоставляет приложениям гибкий способ децентрализованного обмена информацией, гарантируя, что данные останутся в безопасности и защищены от несанкционированного доступа.

Создатели и получатели

В предложении уровня данных производитель и получатель соглашаются изменить свои соответствующие хранилища данных определенным образом, как указано в списке включений. Производитель предоставляет идентификатор магазина, который они хотят изменить, и список обновлений, которые они планируют сделать. Берущий, в свою очередь, получает идентификатор магазина, который производитель хочет изменить, и список обновлений, которые производитель запрашивает взамен. Это позволяет обеим сторонам обмениваться данными атомарным образом, гарантируя, что изменения вносятся одновременно и без помех. Чтобы создать предложение на уровне данных, производитель и получатель должны согласовать предлагаемые изменения и идентификаторы магазинов, которые необходимо изменить. Важно отметить, что указанные идентификаторы магазинов должны принадлежать каждой стороне. В традиционном предложении любая сторона может принять предложение, в предложении уровня данных принять предложение может только сторона, владеющая указанным идентификатором магазина.

Создание предложения

Вот пример использования /make_offer RPC для создания предложения.

curl --location --request POST 'https://<node_url>:8562/make_offer' \
--header 'Content-Type: application/json' \
--data-raw '{
  "maker": [
    {
      "store_id": "a92f96e3d6e893f23ac6783e289495d5e9821df3ee5962a9fea5fdfdcc5048f1",
      "inclusions": [
        {
          "key": "70726f6a6563742d34",    
          "value": "7b2070726f6a6563744e616d653a2022666f6f22207d"
        }
      ]
    }
  ],
  "taker": [
    {
      "store_id": "a92f96e3d6e893f23ac6783e289495d5e9821df3ee5962a9fea5fdfdcc5048f1",
      "inclusions": [
        {
          "key": "70726f6a6563742d34",    
          "value": "7b2070726f6a6563744e616d653a202262617222207d"
        }      
      ]
    }
  ],
  "fee": 0
}'

Важно отметить, что, в отличие от списка изменений, все в списке включений рассматривается как upsert, что означает, что данные на каждой стороне могут быть обновлены или заменены, но в настоящее время нет возможности удалить пару ключ/значение в предложение.

Кроме того, производитель может включить необязательный "fee” для предоплаты комиссии за транзакцию в блокчейне. У получателя также есть возможность использовать эту комиссию или добавить ее позже. Хотя и мейкер, и тейкер могут отказаться от комиссии, это не рекомендуется, поскольку это может привести к неопределенности времени обработки транзакции, которая будет зафиксирована в блокчейне.

Ответ от /make_offer RPC представляет собой «Файл предложения», который представляет собой представление предлагаемых корректировок базы данных, согласованных производителем и получателем. Этот файл можно сохранить как текстовый файл и отправить другой стороне для просмотра и возможного принятия. Принятие предложения повлечет за собой согласованные одновременные корректировки обеих баз данных.

Отмена предложения

Когда файл предложения сгенерирован, ожидающая транзакция будет открыта в кошельке. Это не позволит пользователю совершать дополнительные транзакции, пока предложение не будет принято или отменено. Если производитель хочет отменить предложение, он может вызвать следующий RPC. Это закроет ожидающую транзакцию и позволит пользователю совершать дополнительные транзакции. Важно иметь эту функцию, поскольку она помогает поддерживать целостность уровня данных, предотвращая изменения, пока действует ожидающее предложение.

curl --location --request POST 'https://<node_url>:8562/make_offer' \
--header 'Content-Type: application/json' \
--data-raw '{ 
              "trade_id": "4e9cb14186b13b4fc043015efe213f5a4c507d8f837914647a19825e6d05dfa9",
              "secure": true,
              "fee": 300000
             }'

“trade_id” можно найти в файле предложения.

Проверка предложения

Чтобы проверить действительность предложения, получатель может использовать RPC /verify_offer для получения текущего статуса предложения. Если в ответе указано, что предложение все еще открыто и не отменено, получатель может продолжить принятие предложения.

curl --location --request POST 'https://<node_url>:8562/verify_offer' \
--header 'Content-Type: application/json' \
--data-raw '{
    "fee": 0,
    "offer": <the contents of the offer file> 
}'

Предлагаемые изменения будут в файле предложения в шестнадцатеричном формате. Рекомендуется, чтобы ваше приложение расшифровывало эту информацию и отображало ее получателю, чтобы он мог просмотреть содержимое предложения и понять изменения, которые он собирается принять, прежде чем вносить изменения. решение.

Принятие предложения

Как только получатель подтвердит, что предложение не устарело, и он доволен предложенными изменениями, он может приступить к принятию предложения. Это приведет к одновременному изменению баз данных уровня данных двух сторон, как указано в файле предложения и соответствующей корректировке в ответе. Это гарантирует, что обе стороны согласны с одними и теми же изменениями и что обмен является атомарным, что означает, что либо происходят оба изменения, либо не происходит ни одного, так что ни одна из сторон не может остаться в несогласованном состоянии.

Предложение можно принять с помощью /take_offer RPC:

curl --location --request POST 'https://<node_url>:8562/take_offer' \
--header 'Content-Type: application/json' \
--data-raw '{
    "fee": 0,
    "offer": <the contents of the offer file> 
}'

Вот и все, предложение завершено и соответствующие корректировки завершены.

Заключение

Уровень данных предлагает разработчикам новый способ создания мощных одноранговых приложений в сети Chia. В будущих постах я рассмотрю различные типы приложений, которые можно создать на уровне данных, и то, как их можно спроектировать и реализовать.