Перейти к содержанию

ABI смарт-контракта

ABI (Application Binary Interface) — JSON-схема соответствия между текстовым/JSON-представлением аргументов действий и структур таблиц с бинарной сериализацией в транзакции. Узел исполняет WASM независимо от ABI; последний критичен для клиентов, кошельков и индексаторов. Генерация ABI в CDT снижает расхождения с кодом, однако контроль совместимости остаётся на разработчике.

Соответствие типов C++ контрактного API полям ABI и низкоуровневые детали сериализации — в документации CDT (Doxygen).

ABI не является «входным фильтром»

Транзакция может содержать данные, не совпадающие с ABI: узел исполняет WASM. ABI нужен кошелькам, обозревателям и SDK для удобства и безопасности на стороне клиента.


Генерация и ручное редактирование

Утилита cdt-cpp с флагом -abigen (и корректными атрибутами в коде) создаёт ABI автоматически. Ручное редактирование нужно, если:

  • генератор «спотыкается» о сложные шаблоны C++;
  • используются нестандартные типы;
  • требуются расширения ABI (variants, optional-поля через $ и т.д.).

Пустой каркас:

{
   "version": "eosio::abi/1.1",
   "types": [],
   "structs": [],
   "actions": [],
   "tables": [],
   "ricardian_clauses": [],
   "abi_extensions": []
}

Секция types

Описывает псевдонимы типов. Встроенные типы цепочки в ABI дублировать не нужно (их набор определяется сериализатором узла; список смотрите в исходниках abi_serializer вашей версии узла).

Пример псевдонима:

{
   "new_type_name": "account_name",
   "type": "name"
}

Секции structs и fields

Каждая структура:

{
   "name": "transfer",
   "base": "",
   "fields": [
      { "name": "from", "type": "name" },
      { "name": "to", "type": "name" },
      { "name": "quantity", "type": "asset" },
      { "name": "memo", "type": "string" }
   ]
}
  • Неявные структуры соответствуют параметрам публичных действий, для которых нет отдельного struct в C++.
  • Явные структуры описывают строки таблиц [[eosio::table]].

Поле base задаёт наследование от другой структуры в том же ABI (редко; должно соответствовать логике C++).


Секция actions

{
  "name": "transfer",
  "type": "transfer",
  "ricardian_contract": ""
}
  • name — имя действия в цепочке.
  • type — имя struct с полями параметров (часто совпадает с name, но это не обязательно).
  • ricardian_contract — текст Ricardian или пустая строка, если подключается из внешнего файла при сборке.

Секция tables

{
  "name": "accounts",
  "type": "account",
  "index_type": "i64",
  "key_names": ["currency"],
  "key_types": ["uint64"]
}

Имена ключей могут совпадать между таблицами — это лишь подсказка для клиентов; важно соответствие типов и struct.


Векторы

Тип массива записывается как тип[], например permission_level[].


Ricardian: файлы и разметка

Генератор подхватывает:

  • договоры действий — файл <имя_контракта>.contracts.md;
  • общие клаузы — <имя_контракта>.clauses.md.

Для каждого действия в markdown используйте заголовок:

<h1 class="contract">ИмяДействия</h1>

Для клаузы:

<h1 class="clause">ИдентификаторКлаузы</h1>

Чтобы ABI-генератор нашёл файлы в произвольных каталогах, передайте -R<путь> в cdt-cpp (аналогично -I для include). Пример из upstream: examples/hello/ricardian/hello.contracts.md.


Атрибуты C++ для генератора ABI

[[eosio::action]]

Помечает метод как действие. Альтернатива в стиле GNU: __attribute__((eosio_action)).
Если имя функции не является допустимым именем цепочки:
[[eosio::action("validname")]]

Можно объявлять действие как struct с EOSLIB_SERIALIZE.

[[eosio::table]]

Описание строки таблицы; для явного имени таблицы: [[eosio::table("tablename")]].

[[eosio::contract("name")]]

Привязывает класс к имени контракта для генерации, чтобы заголовки чужих контрактов не попадали в ваш ABI.

[[eosio::on_notify("acct::action")]]

Обработчик уведомлений о чужом действии; шаблон *::transfer — любой контракт.

[[eosio::wasm_entry]] / eosio_wasm_import

Расширенные сценарии сборки WASM для других окружений.

[[eosio::action, eosio::read-only]]

Действие только чтения; ограничения см. Действия и авторизация.


Обслуживание ABI

При каждом изменении:

  • параметров действий;
  • полей таблиц;
  • имён таблиц;

обновляйте ABI. Ошибки при этом часто не возникают, а клиенты начинают слать неверный JSON — отлаживайте через сравнение с cdt-abidiff (см. Справочник команд).

Таблица «пустая» в клиенте

Проверьте, что секция tables и type указывают на существующий struct с верными полями. cleos может не ругаться на плохой ABI, но вернёт пустой результат.


abi_extensions и прочее

abi_extensions зарезервировано под будущие расширения формата; сейчас обычно пусто. Ricardian-тексты описывают намерение действия для пользователя.


Где углубиться