Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
chebykin
7 лет назад

EOSDEV #2. Пишем Hello World смарт-контракт для EOS

Предыдущая статья

Теория

Так же, как и в Ethereum, разработчики сети EOS предлагают нам воспользоваться смарт контрактами для реализации логики запускаемых в ней приложений. Но в отличии от Ethereum, EOS не будет зацикливаться на какой то конкретной реализации виртуальной машины для запуска смарт контрактов. Спецификация предполагает, что изначально будут реализованы два варианта машины, но в дальнейшем их список может расшириться.

Первая предлагаемая виртуальная машина для запуска приложений будет использовать стандарт WebAssembly (WASM), который сейчас становится довольно популярным в веб-среде, позволяя разрабатывать высокопроизводительные приложения для работы в браузерах. С помощью небольших костылей (англ. - modifications) эти приложения можно будет ограничить от влияния внешнего мира и сделать детерминистическими, что позволит использовать их для имплементации смарт-контрактов. Хочу заметить, что команда Ethereum также работает над возможностью написания смарт-контрактов с помощью WebAssembly.

Второй вариант виртуальной машины, которую нам обещают реализовать - Ethereum Virtual Machine (EVM) из соответствующего проекта. Предполагается, что существующие смарт-контракты можно будет запустить в песочнице этой виртуальной машины без или с небольшими модификациями.

Для реализации нашего hello world мы продолжим рассматривать WASM, т.к. пока не известно, когда будет реализована поддержка платформы EVM. Сейчас для разработки смарт-контрактов нам предлагается язык C/C++. Хипстерам думаю не очень понравится эта идея и они потребуют чего то более модного и высокоуровнего. Разработчики предусмотрели это и обещают реализовать поддержку чуть более высокоуровневых языков, таких как Rust, Solidity к лету 2018 года.

Практика

Генерим hello world

Для практики нам понадобится утилита eoscpp, которая находится в папке ./build/tools собранного проекта. Если вы не установили все собранные компоненты на системном уровне (make install в папке ./build), то рекомендую как минимум сделать это для утилиты eoscpp:

cd ./build/tools/
make install

Теперь мы можем воспользоваться ей откуда угодно, чтобы создать новый проект под названием hello:

eoscpp -n hello

В папке hello мы обнаружим 3 файла:

  • hello.abi - ABI интерфейс к бинарному контракту в формате JSON, аналогичный применяемому в Ethereum, но с другим синтаксисом
  • hello.cpp - исходный код контракта
  • hello.hpp - хедер файл для исходного кода контракта

Заглянем в файл hello.cpp:

/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#include <hello.hpp>

/**
 *  The init() and apply() methods must have C calling convention so that the blockchain can lookup and
 *  call these methods.
 */
extern "C" {

    /**
     *  This method is called once when the contract is published or updated.
     */
    void init()  {
       eos::print( "Init World!\n" );
    }

    /// The apply method implements the dispatch of events to this contract
    void apply( uint64_t code, uint64_t action ) {
       eos::print( "Hello World: ", eos::Name(code), "->", eos::Name(action), "\n" );
    }

} // extern "C"

Мы имеем 2 основные функции смарт контракта.

Первая из них, init(), будет выполнена при деплое или передеплое контракта. Здесь необходимо выполнять первоначальную инициализацию стейта приложения.

Вторая это apply(), которая по сути является обработчиком происходящих в сети событий. Разработчики также сравнивают ее с функцией main() в обыкновенном приложении на C. Функция apply() вызывается с двумя аргументами - code и action. Кодом, например, может быть контракт currency, а в качестве действия вызываться transfer. В паре, эти два аргумента образуют уникальный идентификатор события, происходящего в сети. Оно может быть отправлено определенной группе контрактов, в которую могут входить как получатели сообщения, так и его отправитель. Логика смарт-контракта должна сама определять - обрабатывать это событие или нет. В данном примере мы просто выводим в лог любые входящие значения аргументов code и action.

Деплоим

С помощью все той же утилиты eoscpp, мы можем скомпилировать наш hello world пример в wast файл:

eoscpp -o hello.wast hello.cpp

Далее нам понадобится запущенный демон ноды (eosd), как его установить и запустить я описывал в предыдущем посте. С помощью консольного клиента (eosc), мы создадим кошелек (wallet) и импортируем первичный аккаунт (account). Что значат эти термины в блокчейне EOS я опишу в ближайших постах:

eosc wallet create
eosc wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

Ключ 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 в последней строке является WIF ключом первичного аккаунта, который мы импортируем в кошелек. Взялся этот ключ из файла ./build/programs/data-dir/config.ini. Последующие операции будем выполнять также от имени этого аккаунта.

Теперь, указав аккаунт, мы можем развернуть наш Hello World контракт:

eosc set contract inita hello.wast hello.abi

На что получим красноречивый json ответ об успешном деплое контракта:

Reading WAST...
Assembling WASM...
Publishing contract...
{
  "transaction_id": "01a7cb37a5632e563f7a271a8ecfda3e2191bfe73a76d2142db32427427832f0",
  "processed": {
    "refBlockNum": 283,
    "refBlockPrefix": 3855761785,
    "expiration": "2017-10-30T17:04:39",
    "scope": [
      "eos",
      "inita"
    ],
    "signatures": [
      "20413f96262d6f2a39d76476994b756c197da730e62d2325ed78c57f0179fb5b0f58db691de1bf2ccec33bb6d9b14d8a36993aff00014b2883e65b861fd2d65fff"
    ],
    "messages": [{
        "code": "eos",
        "type": "setcode",
        "authorization": [{
            "account": "inita",
            "permission": "active"
          }
        ],
        "data": "000000000093dd740000f1010061736d0100000001110460017f0060017e0060000060027e7e00021b0203656e76067072696e746e000103656e76067072696e7473000003030202030404017000000503010001071903066d656d6f7279020004696e69740002056170706c7900030a20020600411010010b17004120100120001000413010012001100041c00010010b0b3f050041040b04504000000041100b0d496e697420576f726c64210a000041200b0e48656c6c6f20576f726c643a20000041300b032d3e000041c0000b020a000029046e616d6504067072696e746e0100067072696e7473010004696e697400056170706c790201300131010b4163636f756e744e616d65044e616d6502087472616e7366657200030466726f6d0b4163636f756e744e616d6502746f0b4163636f756e744e616d6506616d6f756e740655496e743634076163636f756e740002076163636f756e74044e616d650762616c616e63650655496e74363401000000572d3ccdcd087472616e7366657201000000204f4d11320369363401076163636f756e7401044e616d65076163636f756e74"
      }
    ],
    "output": [{
        "notify": [],
        "deferred_transactions": []
      }
    ]
  }
}

Особенности обработки транзакций

Если мы посмотрим в лог демона eosd, то заметим, что фраза Init World отобразилась 3 раза:

img1.png

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

  • Первый раз Init World печатается нодой при запуске транзакции в песочнице, думаю это необходимо для валидации того, что все пройдет успешно
  • Второй раз Init World печатается нодой-продюсером блока при его сборке
  • Третий раз Init World печатается нодой при принятии блока от любого из продюсеров, в т.ч. и от себя

Не очень явно, но думаю, скоро нам дадут пояснения.

Отправляем сообщение нашему контракту

Теперь мы можем послать сообщение развернутому ранее контракту

eosc push message inita ping '"abcd"' --scope inita

Разберем команду более детально:

  • eosc push message - отправить сообщение смарт-контракту
  • inita - аккаунт, от которого отправляем сообщение
  • ping - действие action
  • '"abcd"' - фейковые бинарные данные, в рабочем примере на их месте должен быть JSON, структура которого описывается в .abi файле

В ответ получим JSON об успешной отправке сообщения:

{
  "transaction_id": "c16bca4afb355238e19e56aeb36cca5cc2d9e0dd48fb4069affe470b59be2647",
  "processed": {
    "refBlockNum": 735,
    "refBlockPrefix": 3432130105,
    "expiration": "2017-10-30T17:29:48",
    "scope": [
      "inita"
    ],
    "signatures": [],
    "messages": [{
        "code": "inita",
        "type": "ping",
        "authorization": [],
        "data": "abcd"
      }
    ],
    "output": [{
        "notify": [],
        "deferred_transactions": []
      }
    ]
  }
}

Обратите внимание, что демон eosd, также как и в случае с разворачиванием контракта, выводит в лог посланное нами сообщение 3 раза ¯¯\(ツ)/¯¯:

img3.png

На сегодня все

Теперь мы можем смело бежать покупать токены EOS, чтобы меньше чем через год иметь возможность запустить свое Hello World приложение на реально работающей сети.

В следующем посте мы разберем, как модифицировать данный пример, добавив в него немного логики.

3
4.354 GOLOS
На Golos с July 2017
Комментарии (2)
Сортировать по:
Сначала старые