Эксперименты с контрактами Solidity в тестовой сети Rinkeby блокчейна Ethereum

в 14:07, , рубрики: dapp, devops, Ethereum, geth, Rinkeby, solidity, web3.js, блокчейн, криптовалюта, Разработка под e-commerce, смарт-контракт

Эксперименты с контрактами Solidity в тестовой сети Rinkeby блокчейна Ethereum - 1

Эта статья представляет собой небольшое практическое руководство, которое поможет вам быстро настроить среду разработки смарт-контрактов на языке Solidity для блокчейна Ethereum. Вы опубликуете первый контракт, сохраните его в тестовом блокчейне Rinkeby и научитесь вызывать методы контракта. Это будет ваш первый шаг на пути создания децентрализованных приложений DApp (Decentralized Application).

Несмотря на обилие книг, статей и руководств, посвященной теме этой статьи, новичку довольно трудно приступить к публикации контрактов и работе с ними. При попытке что-то сделать по книгам, руководствам и статьям нередко оказывается, что примеры не работают, а команды возвращают непонятные ошибки. Я попытаюсь в некоторой степени упростить первый этап освоения, отразив в этой статье свой опыт изучения Ethereum.

При погружении в эту тему я использовал приложение (браузер) Mist в среде Microsoft Windows, а также интерфейс командной строки Geth узла Ethereum в среде Ubuntu. В этой статье мы расскажем о работе с Geth, а также немного о том, как вызывать методы контрактов из Node.js.

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

Погружение в тему

Прежде чем начинать создание смарт-контрактов, я рекомендую изучить технологию блокчейна (Blockchain). Например, для начала вы можете почитать статью Объяснение блокчейна для веб-разработчиков, опубликованную на Хабре.

Ethereum — это децентрализованная платформа для разработки смарт-контрактов и создания так называемых децентрализованных приложений DApp. Сайт Ethereum находится по адресу https://www.ethereum.org/. Здесь вы найдете ссылки на основные ресурсы, которые будут вам полезны.

Например, по адресу http://www.ethdocs.org/en/latest/ опубликована документация платформы.

Руководство по языку Solidity находится здесь. Имеется перевод на русский язык, который, однако, может отставать от оригинальной документации.

По ходу изложения материала мы будем делать ссылки на те или иные ресурсы.

Установка узла Ethereum на виртуальной машине Ubuntu

Для публикации контрактов и работы с Ethereum обычным пользователям компьютеров будет проще использовать браузер Mist с визуальным интерфейсом в среде Microsoft Windows. Однако разработчикам программного обеспечения (ПО) для понимания происходящего будет полезнее иметь дело с командной строкой.

Мы установим Go Ethereum — одну из трех оригинальных реализаций протокола Ethereum, написанную на языке Go (еще есть реализации на С++ и Python).

Go Ethereum можно установить на серверные платформы Ubuntu, Arch Linux и FreeBSD. Я выбрал Ubuntu, так как она похожа на Debian, а Debian мы применяем на нашем сервисе интернет-магазинов. Для эксперимента я установил ОС Ubuntu 17.10 на виртуальную машину под управлением VMWare Workstation.

Срзу после установки Ubuntu нужно добавить возможность подключения через SSH. Дополнительно я установил редактор Vim:

sudo apt-get install ssh
sudo apt-get install vim

Далее нужно установить стабильный релиз Go Ethereum:

sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum

Полностью этот процесс описан здесь.

Теперь нам нужно установить полный узел (full node) тестовой сети Rinkeby. Инструкция для узлов различного типа находится здесь: https://www.rinkeby.io/#geth. Нам нужен блок этой инструкции для полного узла.

Прежде всего, копируем файл rinkeby.json в домашний каталог отсюда: https://www.rinkeby.io/rinkeby.json.

Далее открываем первое консольное окно, создаем в домашнем каталоге папку rinkeby и запускаем команду:

geth --datadir=/home/frolov/rinkeby init rinkeby.json

Эта команда запускается только один раз при инициализации. Здесь предполагается, что данные узла будут храниться в каталоге /home/frolov/rinkeby, а файл rinkeby.json — в каталоге /home/frolov/. Разумеется, вы можете выбрать другое расположение каталогов.

После завершения инициализации в этом же окне запускаем geth со следующими параметрами (вместо shop2you в параметре ethstats укажите какое-нибудь свое уникальное имя):

geth --networkid=4 --datadir=/home/frolov/rinkeby --rpc --rpcaddr "0.0.0.0" --rpcapi "admin,debug,miner,shh,txpool,personal,eth,net,web3" --ethstats='shop2you:Respect my authoritah!@stats.rinkeby.io' --bootnodes=enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303

Описание параметров команда geth вы можете найти по адресу https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options. Также можно посмотреть справку по параметрам geth с помощью команды:

geth --help

Параметр --networkid=4 указывает, что мы используем тестовую сеть Rinkeby. С помощью параметра --datadir мы задаем расположение каталога для хранения базы данных узла и ключей.

Параметр --rpc разрешает работу сервера HTTP-RPC. Мы будем подключаться к нашему узлу из второго консольного окна через этот сервер. С помощью параметра --rpcaddr мы указываем, что сервер работает на всех сетевых интерфейсах узла (по умолчанию только на localhost). При помощи параметра --rpcapi мы указываем, какие API будут доступны через интерфейс HTTP-RPC.

Параметр --ethstats указывает URL-адрес отчета службы ethstats и задается в формате nodename:secret@host:port. И, наконец, параметр --bootnodes задает URL-адреса для загрузки P2P (Comma separated enode URLs for P2P discovery bootstrap).

Итак, мы запустили узел Go Ethereum для сети Rinkeby в первом консольном окне. Во втором консольном окне подключаемся к этому узлу с помощью такой команды:

geth --networkid=4 --datadir=/home/frolov/rinkeby attach ipc://home/frolov/rinkeby/geth.ipc

После подключения вы увидите командное приглашение утилиты geth. Введите в нем следующую команду:

> web3.version
{
  api: "0.20.1",
  ethereum: "0x3f",
  network: "4",
  node: "Geth/v1.7.3-stable-4bb3c89d/linux-amd64/go1.9.1",
  whisper: undefined,
  getEthereum: function(callback),
  getNetwork: function(callback),
  getNode: function(callback),
  getWhisper: function(callback)
}

Эта команда покажет версию программного интерфейса Web3, с помощью которого мы будем работать с контрактами, версию geth, а также номер сети, который для Rinkeby равен 4.

Синхронизация узла

Прежде чем продолжить работу, необходимо дождаться окончания синхронизации узла. Запустите во втором окне в приглашении geth команду eth.syncing:

> eth.syncing
{
  currentBlock: 404158,
  highestBlock: 1402511,
  knownStates: 1974866,
  pulledStates: 1962021,
  startingBlock: 0
}

Так вы не запускаете процесс синхронизации (он должен запуститься автоматически), но, повторяя время от времени запуск команды, сможете отслеживать ход процесса. Когда синхронизация будет завершена, команда вернет false:

> eth.syncing
false

Процесс синхронизации можно наблюдать в первом консольном окне, в котором мы запустили узел Go Ethereum:

...
INFO [12-13|10:00:37] Imported new chain segment               blocks=1   txs=1   mgas=0.123  elapsed=21.839ms  mgasps=5.610   number=1408525 hash=bd6e8b…745ca3
INFO [12-13|10:00:51] Imported new chain segment               blocks=1   txs=22  mgas=1.379  elapsed=188.490ms mgasps=7.317   number=1408526 hash=924b25…b292de
INFO [12-13|10:00:51] Imported new chain segment               blocks=1   txs=22  mgas=1.379  elapsed=162.386ms mgasps=8.493   number=1408526 hash=c05478…70b24c
INFO [12-13|10:00:51] Imported new chain segment               blocks=1   txs=22  mgas=1.379  elapsed=165.818ms mgasps=8.317   number=1408526 hash=8961b4…48d0a4
INFO [12-13|10:01:07] Imported new chain segment               blocks=1   txs=2   mgas=0.063  elapsed=4.120ms   mgasps=15.347  number=1408527 hash=a5e658…22d300
...

Заметим, что синхронизация начинается не мгновенно после запуска узел geth, и на ее завершение в сети Rinkeby может уйти достаточно продолжительное время, порядка нескольких десятков минут.

Добавление аккаунтов

Сразу после установки нового узла вам нужно добавить в него аккаунты (если у вас уже есть аккаунты на других узлах, их можно перенести на новый узел).

Для добавления аккаунта введите в приглашении geth команду personal.newAccount():

> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3"

Здесь вам нужно будет ввести пароль. При работе с настоящей, не тестовой сетью Ethereum, нужно особенно позаботиться о сохранении пароля. Лучше всего не записывать пароль на компьютер, даже на зашифрованный диск. Дело в том, что вирусы или троянские программы смогут похитить пароль с зашифрованного диска, т.к. когда вы работаете с диском, его содержимое становится доступным. Также существуют кей-логгеры, которые могут перехватить пароль при его вводе с клавиатуры.

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

После ввода пароля на консоли появится адрес аккаунта, в нашем случае это «0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3» (у вас будет другой адрес). Заметим, что адреса созданных аккаунтов записывать не обязательно, т.к. их можно посмотреть при помощи команды eth.accounts:

> eth.accounts
["0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3"]

Вы можете добавить подобным образом несколько аккаунтов. В этом случае команда выведет массив идентификаторов для всех аккаунтов:

> eth.accounts
["0xa15862b34abfc4b423fe52f153c95d83f606cc97", "0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3", "0x957f5272eadf4e284aade9b2cb2a41f475936d07"]

Для каждого аккаунта создается приватный ключ. В нашем случае все ключи находятся в каталоге /home/frolov/rinkeby/keystore. Рекомендую сохранить эти ключи в безопасном месте, особенно если они относятся к аккаунтам основной, а не тестовой сети.

Пополнение аккаунта эфиром

Для того чтобы можно было публиковать контракты и вызывать их методы, необходимо пополнить кошелек эфиром (Ether). Текущий баланс можно проверить следующей командой:

> web3.fromWei( eth.getBalance(eth.coinbase) )
0

Этой команде также можно предавать идентификатор аккаунта:

> web3.fromWei( eth.getBalance("0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3") )
10.428648202959703389

Чтобы пополнить кошелек в тестовой сети Rinkeby вам не потребуются реальные бумажные деньги или криптовалюта. Воспользуйтесь сайтом https://faucet.rinkeby.io/. Вам также потребуется аккаунт в Google+, Facebook или Twitter.

Сделайте публикацию в одной из перечисленных социальных сетей, содержащую адрес вашего аккаунта, такой как 0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3 (у вас будет другой адрес).

Далее скопируйте адрес публикации в поле Social network URL containing your Ethereum address и выберите из списка Give me Ether одно из значений.

Здесь вы можете получать 3 Ethers каждые 8 часов, 7.5 Ethers каждый день или 18.75 Ethers каждые три дня. Для начала работы вам вполне хватит 3 Ethers, так что можете выбирать первый вариант.

Если вы все сделали правильно, через некоторое время «эфирчики» поступят на ваш аккаунт. Разумеется, эти средства вы сможете потратить только в тестовой сети Rinkeby.

Контракт для публикации

Теперь, когда вы все установили и проверили, пополнили свой аккаунт, можно приступать к публикации контракта. Мы будем работать с очень простым контрактом HelloSol. Вот его исходный текст на языке Solidity:

pragma solidity ^0.4.10;

contract HelloSol {
    string savedString;
    uint savedValue;
    function setString( string newString ) public {
        savedString = newString;
    }
    function getString() public constant returns( string ) {
        return savedString;
    }
    function setValue( uint newValue ) public {
        savedValue = newValue;
    }
    function getValue() public constant returns( uint ) {
        return savedValue;
    }
}

Этот контракт позволяет хранить текстовую строку и числовое значение. С помощью методов setString и getString можно, соответственно, записывать и читать строки. Аналогичные методы setValue и getValue предусмотрены для числовых значений.

Я создал три тестовых аккаунта:

> eth.accounts
["0xa15862b34abfc4b423fe52f153c95d83f606cc97", "0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3", "0x957f5272eadf4e284aade9b2cb2a41f475936d07"]

Для публикации контракта я буду использовать последний из них с адресом 0x957f5272eadf4e284aade9b2cb2a41f475936d07. На этот адрес можно ссылаться следующим образом:

> web3.eth.accounts[2]
"0x957f5272eadf4e284aade9b2cb2a41f475936d07"

Убедимся, что на аккаунте accounts[2] имеются средства:

> web3.fromWei( eth.getBalance(web3.eth.accounts[2]));
1.49157544347657552

Перед публикацией контракта (а также перед вызовом методов контракта, изменяющих данные), необходимо разблокировать аккаунт. Это можно сделать при помощи метода personal.unlockAccount:

> personal.unlockAccount(eth.accounts[2])
Unlock account 0x957f5272eadf4e284aade9b2cb2a41f475936d07
Passphrase:
true

У вас будет запрошен пароль, который вы задавали при создании аккаунта.

Компиляция контракта

Далее нам нужно создать для контракта так называемый Application Binary Interface (ABI), а также выполнить компиляцию исходного текста контракта, написанного на языке Solidity.

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

В результате компиляции исходного текста контракта, написанного на Solidity, должен получиться бинарный код программы, который будет выполнять виртуальные машины на всех узлах сети Ethereum. В нашем случае это будет только тестовая сеть Rinkeby.

Интерфейс ABI и бинарный код программы проще всего получить при помощи браузерного инструмента IDE Remix, доступного по адресу https://remix.ethereum.org. Руководство по использованию Remix можно найти здесь.

Откройте в браузере IDE Remix, и скопируйте код нашего контракта HelloSol в окно исходного текста, как это показано на рисунке ниже:

Эксперименты с контрактами Solidity в тестовой сети Rinkeby блокчейна Ethereum - 2

По умолчанию код будет сразу же откомпилирован, т.к. установлен флажок Auto compile. Чтобы получить ABI и двоичный код, щелкните кнопку Details. Найдите в появившемся окне блок web3Deploy:

Эксперименты с контрактами Solidity в тестовой сети Rinkeby блокчейна Ethereum - 3

Скопируйте отсюда блок кода при помощи кнопки Copy value to clipboard и вставьте этот текст в какой-нибудь текстовый редактор, например, в редактор Vim.

Публикация контракта

Для того чтобы опубликовать контракт, достаточно вставить из буфера обмена блок кода, скопированный из Remix, и нажать клавишу Enter.

Перед тем как это сделать, я отредактировал строку from: web3.eth.accounts[0], заменив ее на from: web3.eth.accounts[2]. Это было сделано, чтобы выполнить публикацию от аккаунта web3.eth.accounts[2], на котором имеются средства. Если вы создали только один аккаунт и пополнили его эфиром, то ничего редактировать не нужно, просто вставьте в окно консоли в приглашении программы geth текст, скопированный из Remix:

> var browser_ballot_sol_hellosolContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newValue","type":"uint256"}],"name":"setValue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newString","type":"string"}],"name":"setString","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getString","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]);
 undefined
> var browser_ballot_sol_hellosol = browser_ballot_sol_hellosolContract.new(
...    {
......      from: web3.eth.accounts[2],
......      data: '0x6060604052341561000f57600080fd5b6103598061001e6000396000f300606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063209652551461006757806355241077146100905780637fcaf666146100b357806389ea642f14610110575b600080fd5b341561007257600080fd5b61007a61019e565b6040518082815260200191505060405180910390f35b341561009b57600080fd5b6100b160048080359060200190919050506101a8565b005b34156100be57600080fd5b61010e600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506101b2565b005b341561011b57600080fd5b6101236101cc565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610163578082015181840152602081019050610148565b50505050905090810190601f1680156101905780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000600154905090565b8060018190555050565b80600090805190602001906101c8929190610274565b5050565b6101d46102f4565b60008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561026a5780601f1061023f5761010080835404028352916020019161026a565b820191906000526020600020905b81548152906001019060200180831161024d57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106102b557805160ff19168380011785556102e3565b828001600101855582156102e3579182015b828111156102e25782518255916020019190600101906102c7565b5b5090506102f09190610308565b5090565b602060405190810160405280600081525090565b61032a91905b8082111561032657600081600090555060010161030e565b5090565b905600a165627a7a7230582072dd1e3c0f509e8064320e887b19eb36fb41842f0897f41ce216a146c342d6140029',
......      gas: '4700000'
......    }, function (e, contract){
......     console.log(e, contract);
......     if (typeof contract.address !== 'undefined') {
.........          console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
.........     }
......  })

Как только вы скопируете текст, то увидите в консоли следующее:

null [object Object]
undefined
> null [object Object]

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

Contract mined! address: 0x11c63c5ebc2c6851111d881cb58c213c609c92d4 transactionHash: 0xe79342277d7e95cedf0409e0887c2cddb3ebc5f0d952b9f7c1c1c5cef845cb97

Теперь ваш контракт опубликован в сети Rinkeby, и ему присвоен адрес 0x11c63c5ebc2c6851111d881cb58c213c609c92d4. Пользуясь этим адресом, любой пользователь сети Rinkeby сможет обращаться к контракту, вызывая его методы.

Вызов методов контракта

Теперь займемся самым интересным — взаимодействием с контрактом. Мы будем вызывать его методы из консоли geth, используя API JavaScript Web3, описанный здесь. Заметим, что это документация на стабильную версию Web3 0.2x.x. Есть еще не реализованная версия 1.0, описанная по адресу http://web3js.readthedocs.io/en/1.0/index.html.

Прежде всего, в консольном приглашении Geth введите следующую строку:

var HelloSolContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newValue","type":"uint256"}],"name":"setValue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newString","type":"string"}],"name":"setString","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getString","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]);

Здесь на основе ABI будет создан объект нашего контракта. Вызовем для него метод at, передав этому методу в качестве параметра адрес контракта 0x11c63c5ebc2c6851111d881cb58c213c609c92d4, полученный нами на шаге публикации контракта:

var HelloSol = HelloSolContract.at("0x11c63c5ebc2c6851111d881cb58c213c609c92d4");

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

> HelloSol.getValue()
0

Перед тем как вызывать метод setValue, нам необходимо разблокировать аккаунт при помощи метода unlockAccount:

> personal.unlockAccount(eth.accounts[2])
Unlock account 0x957f5272eadf4e284aade9b2cb2a41f475936d07
Passphrase:
true

Если вы помните, ранее мы разблокировали аккаунт перед публикацией контракта.

После того как аккаунт разблокирован, вызываем метод setValue:

> HelloSol.setValue(777, {from: "0x957f5272eadf4e284aade9b2cb2a41f475936d07"})
"0x019131872a3a834a1aaad7a810977eaaa1f9131344b9fb96e57d21a3f08c1363"

Обратите внимание, что в качестве первого параметра мы передаем методу значение, которое должно быть сохранено, а в качестве второго — адрес аккаунта, от имени которого будет вызван этот метод.

Теперь попытаемся получить значение методом getValue:

> HelloSol.getValue()
0
> HelloSol.getValue()
777

Вначале этот метод будет возвращать нулевое значение, и только через некоторое время мы получим наше новое значение.

Аналогичный эксперимент мы можем провести и с методами getString и setString, которые извлекают из базы контракта и изменяют в базе текстовую строку, соответственно:

> HelloSol.getString()
""
> personal.unlockAccount(eth.accounts[2])
Unlock account 0x957f5272eadf4e284aade9b2cb2a41f475936d07
Passphrase:
true
> HelloSol.setString("Моя строка", {from: "0x957f5272eadf4e284aade9b2cb2a41f475936d07"})
"0x6a50d48a39d7c8e4d49fcb821a16305059d3064ff25d757bf2877d4aa0a29f31"
> HelloSol.getString()
""
> HelloSol.getString()
""
> HelloSol.getString()
"Моя строка"

Установка пакетного компилятора sol

Небольшие контракты очень удобно отлаживать при помощи IDE Remix. Однако есть и альтернатива — пакетный компилятор solc, который можно запускать в командной строке. Документация по этому компилятору находится здесь.

Я использовал для установки solc следующую команду:

sudo snap install solc

После установки можно узнать версию компилятора:

solc --version
solc, the solidity compiler commandline interface
Version: 0.4.18+commit.9cf6e910.Linux.g++

Давайте выполним компиляцию нашего контракта HelloSol, получив для него файлы, содержащие ABI и двоичный код. Запишите исходный текст контракта в файл HelloSol.sol, а затем выполните следующую команду:

solc --bin --abi HelloSol.sol -o build --overwrite

После ее выполнения в подкаталоге build текущего каталога будут созданы два файла — HelloSol.abi и HelloSol.bin. Первый из них содержит ABI, а второй — двоичный код откомпилированного контракта.

Для деплоя контракта можно использовать приведенный код из Remix, подставив в него результат компиляции — содержимое файлов HelloSol.abi и HelloSol.bin. При этом нужно проследить за тем, чтобы не было переводов строк внутри строк содержимого этих файлов.

Вызов методов контракта из Node.js

Для децентрализованных приложений DApp необходимо сделать пользовательский интерфейс. Можно связать обычное Web-приложение с системой контрактов, например, при помощи сервиса на базе Node.js. Давайте попробуем обратиться к методам нашего контракта через скрипт JavaScript, работающего на сервере под управлением Node.js.

Прежде всего, установим Node.js:

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - 
sudo apt-get install -y nodejs
node -v
v6.11.4

Также нам потребуется npm:

sudo apt install npm
npm -v
3.5.2

На следующем этапе нам нужно будет установить git, а также API Web3, причем стабильной версии. По умолчанию устанавливается нестабильная версия 1.x, поэтому сделаем так:

sudo apt-get install git
npm uninstall web3
npm install web3@0.20.1 --save

Чтобы проверить, что у нас все получилось, запустите в консоли Node.js при помощи команды node. Из консольного приглашения node введите следующие команды:

> var Web3 = require('web3')
undefined
> var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
undefined
> console.log(web3.eth.accounts);
[ '0xa15862b34abfc4b423fe52f153c95d83f606cc97',
  '0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3',
  '0x957f5272eadf4e284aade9b2cb2a41f475936d07' ]

Здесь мы подключились у узлу node и посмотрели список аккаунтов, созданных на этом узле.

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

web3.personal.unlockAccount("0x957f5272eadf4e284aade9b2cb2a41f475936d07", "*********", 1000);
true

Вместо звездочек укажите свой пароль к аккаунту.

Далее вы можете попробовать в приглашении Node.js подключиться к опубликованному ранее контракту и вызвать его методы:

> var HelloSolContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newValue","type":"uint256"}],"name":"setValue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newString","type":"string"}],"name":"setString","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getString","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]);
undefined
> var HelloSol = HelloSolContract.at("0x11c63c5ebc2c6851111d881cb58c213c609c92d4");
undefined
> HelloSol.getValue()
{ [String: '777'] s: 1, e: 2, c: [ 777 ] }
> HelloSol.getString()
'Моя строка'

Мы подготовили скрипт nodejs_web3_test.js, который можно запускать командой «node nodejs_web3_test.js» из консоли Ubuntu:

var Web3 = require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log(web3.eth.accounts);

var HelloSolContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"getValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newValue","type":"uint256"}],"name":"setValue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newString","type":"string"}],"name":"setString","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getString","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]);

var HelloSol = HelloSolContract.at("0x11c63c5ebc2c6851111d881cb58c213c609c92d4");

console.log(HelloSol.getValue().toString(10));
console.log(HelloSol.getString());

web3.personal.unlockAccount("0xa15862b34abfc4b423fe52f153c95d83f606cc97", "*******", 1000);
HelloSol.setString("Моя строка 999", {from: "0xa15862b34abfc4b423fe52f153c95d83f606cc97"});

Этот скрипт подключается к узлу, затем выводит список аккаунтов. Далее он подключается к контракту 0x11c63c5ebc2c6851111d881cb58c213c609c92d4 и вызывает его методы.

Вот что примерно вы увидите на консоли:

node nodejs_web3_test.js
[ '0xa15862b34abfc4b423fe52f153c95d83f606cc97',
  '0x7d9006e7f24bd6d90dd8cc63764ab0b92b77d9b3',
  '0x957f5272eadf4e284aade9b2cb2a41f475936d07' ]
777
Моя строка 123

Заключение

Затронутая мною тема смарт-контрактов слишком масштабна и охватить ее в одной статье невозможно. Тут потребуется очень толстая книга! Я не рассмотрел некоторые очень важные темы, например, экономику Ethereum, единицы работы Gas, фильтры и многое другое. Но у меня есть планы создания новых статей, а возможно, и книги. Мне хотелось бы знать, о чем нужно рассказать в первую очередь, так что я очень жду ваших откликов!

Автор: AlexandreFrolov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js