Взаимодействие со смарт-контрактами с использованием Web3.js (часть II)

Это продолжение Части I.

Резюме
В первой части мы создали нашу среду (Node.js, Web3.js и подключение к узлу Ethereum). Затем был обсужден объект Web3 вместе с основными командами, которые разработчики могут использовать из командной строки узла. Были приведены примеры работы с учетными записями пользователей, запроса блокчейна и отправки транзакции из файла Javascript. В части II будет продолжено взаимодействие со смарт-контрактом в блокчейне.

Обзор
Во второй части мы подробно рассмотрим смарт-контракты и способы взаимодействия с ними с помощью функций библиотеки Web3.js. Мы укажем поставщика Web3 с помощью Ganache (установите конкретную версию для вашей операционной системы), кратко представленного в Части I. Это также важно понимать с точки зрения разработчика, поэтому мы создадим небольшое приложение, использующее язык программирования Solidity с использованием Remix IDE.

Создание смарт-контракта

В Remix IDE мы собираемся создать простую программу, использующую Solidity для смарт-контракта. Мы собираемся использовать версию компилятора 0.8.1 (вы можете использовать любой доступный компилятор), но убедитесь, что нет ошибок компиляции. Для развертывания важно, чтобы код успешно компилировался.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract SimpleContract {
    
    uint public myValue = 50;
    string public myString = "Hello World!";
    
    function setValue(uint _myValue) public {
        myValue = _myValue;
    }
    
    function setString(string memory _myString) public {
        myString = _myString;
    }    
    
}

Смарт-контракт SimpleContract содержит две функции. Это функции-установщики, которые вводят значение, вызывающее изменение состояния. Две переменные состояния определены myValue (целое число) и myString (строка) с присвоенными значениями (50 и "Привет, мир").

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

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

Развертывание в Ganache в качестве поставщика Web3

Прежде чем можно будет развернуть смарт-контракт, должен быть узел Ethereum. В этом примере мы собираемся использовать Ganache, хотя есть и другие провайдеры (обсуждаемые в Части I). Ganache предоставляет тестовую среду, имитирующую цепочку блоков Ethereum. Это позволяет разработчику запускать локальную цепочку блоков, что не требует затрат газа при тестировании приложений.

Сначала запустите Ganache. В этом примере используется версия Truffle с графическим интерфейсом 2.5.4 для macOS (High Sierra 10.13.6). Ganache предоставляет 10 тестовых учетных записей с публичным адресом (адресом Ethereum) и закрытым ключом. Мы будем использовать эти учетные записи для тестирования. Для простоты мы будем использовать самую первую учетную запись Ganache в качестве основной учетной записи пользователя.

В Remix IDE на вкладке Развертывание и выполнение транзакций в разделе Среда выберите Поставщик Web3 в раскрывающемся списке. Убедитесь, что вы выбрали учетную запись (по умолчанию первая учетная запись, предоставленная Ganache), а контракт на развертывание в рамках Контракта - SimpleContract. Когда вас спросят о настройках, убедитесь, что вы указали (URL-адрес и номер порта):

http://127.0.0.1:7545

Номер порта по умолчанию, используемый Ganache, - 7545.

Нажмите кнопку Развернуть, и код будет отправлен в блокчейн поставщика Web3. При успешном развертывании (зеленый кружок с галочкой) в Remix IDE должен быть получен следующий результат:

[block:1 txIndex:0]
from: 0x68c…b843D
to: SimpleContract.(constructor)
value: 0 wei
data: 0x608…50033
logs: 0
hash: 0x525…82507

Разработчики могут начать тестирование смарт-контракта из Remix IDE. Теперь мы будем использовать фреймворк Web3.js для взаимодействия со смарт-контрактом с использованием среды Node.

Взаимодействие со смарт-контрактом

Откройте среду Node из консоли (убедитесь, что вы установили Web3.js, как описано в Части I). Откроется приглашение .

Начнем с требования библиотеки web3 для взаимодействия со смарт-контрактом.

> const Web3 = require('web3')

Это создает объект Web3, который обеспечивает доступ к функциям, которые позволяют взаимодействовать с цепочкой блоков. Теперь нам понадобится конечная точка или провайдер, чтобы подключить нас к блокчейну.

> const web3 = new Web3('http://127.0.0.1:7545')

Укажите поставщика Ganache Web3 как ‘http://127.0.0.1:7545’ или ‘http: // localhost: 7545’. Это связывает нашу среду Node с блокчейном, работающим на Ganache. Чтобы проверить это, просто введите команду вроде:

> web3.eth.getAccounts().then(console.log)

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

> [
'0x68cd5E5C54e8EEB0bC416Ac661eAD2cBdF0b843D',
'0xC65CC917B6c58dfD76B7B3Bd95b9207e2A68AfF5',
'0x52574e8Fd7F8F74e8BEb61E6bA49d0D3310Ff4ec',
'0x52aC19Bf8a91f77847351547e2a32e9e905B0553',
'0x46F1561a2f82708F62e04054b98c33029070Fbb6',
'0x8E2BA163CF1AeF2a9DE03B020819bbF3825D5490',
'0x58aCc72B3A4705C5B030AB0f450D7Ac454E2D2BF',
'0x80bb897BB00831442e2904d027D16D5F2120b569',
'0x30C6C5515C3795a08CE356447C8e188246A90b66',
'0x31F9f4a0F472B6fd2111767C1C7353514156FdF2'
]

Это возвращает доступные учетные записи пользователей в блокчейне Ganache. Это подтверждает, что у нас есть связь.

Теперь мы собираемся создать экземпляр смарт-контракта для среды Node, используя функции Web3. Давайте определим объект контракта под названием contract и создадим смарт-контракт.

> let contract = new web3.eth.Contract(<ABI>, <Contract Address>)

Обратите внимание, что у функции есть два параметра: ‹ABI› и ‹Contract Address›. ABI (двоичный интерфейс приложения) - это формат JSON смарт-контракта, который содержит его функции и методы. Это дает ссылку на то, что вы можете вызвать с помощью библиотеки Web3. Адрес контракта относится к адресу смарт-контракта, который был развернут в цепочке блоков.

Чтобы получить ABI, вернитесь на вкладку Solidity Compiler в Remix IDE. В разделе Контракт есть крошечный значок с надписью ABI. Щелкните значок, и ABI скопируется в буфер обмена. Теперь вставьте ABI в раздел ‹ABI› функции. Это будет выглядеть примерно так:

> let contract = new web3.eth.Contract([
 {
  "inputs": [
   {
    "internalType": "string",
    "name": "_myString",
    "type": "string"
   }
  ],
  "name": "setString",
  "outputs": [],
  "stateMutability": "nonpayable",
  "type": "function"
 },
 {
  "inputs": [
   {
    "internalType": "uint256",
    "name": "_myValue",
    "type": "uint256"
   }
  ],
  "name": "setValue",
  "outputs": [],
  "stateMutability": "nonpayable",
  "type": "function"
 },
 {
  "inputs": [],
  "name": "myString",
  "outputs": [
   {
    "internalType": "string",
    "name": "",
    "type": "string"
   }
  ],
  "stateMutability": "view",
  "type": "function"
 },
 {
  "inputs": [],
  "name": "myValue",
  "outputs": [
   {
    "internalType": "uint256",
    "name": "",
    "type": "uint256"
   }
  ],
  "stateMutability": "view",
  "type": "function"
 }
]

Затем, чтобы получить адрес контракта, перейдите на вкладку Развертывание и выполнение транзакций. В разделе Развернутые контракты вы должны увидеть имя смарт-контракта, который был развернут (SimpleContract). Он содержит адрес смарт-контракта. Щелкните значок копии рядом с названием смарт-контракта, чтобы скопировать адрес смарт-контракта.

Вставьте его после ABI в нашу функцию. (См. Пример ниже)

Примечание. Эти примеры предназначены только для тестирования. Не используйте в производственной среде.

... ], "0xf363f0067E127648Ae7AdE34b7f23CDF3AA91f52")

Нажмите Enter после того, как добавите параметры. Теперь вы можете взаимодействовать со смарт-контрактом (при условии, что ошибки не возвращаются).

Мы используем функцию contract.methods для вызова цепочки блоков. Например, мы можем получить значения myValue.

> contract.methods.myValue().call().then(console.log)
Promise { <pending> }
> 50

Мы также можем выполнить вызов, чтобы получить значение myString.

> contract.methods.myString().call().then(console.log)
Promise { <pending> }
> Hello World!

Мы также можем использовать функцию contract.methods для установки значений наших переменных. Это достигается с помощью одной из функций установки в смарт-контракте, которая называется setValue (). Например, я могу изменить значение myValue на 500, используя следующую команду:

> contract.methods.setValue(500).send({ from: "0x68cd5E5C54e8EEB0bC416Ac661eAD2cBdF0b843D" }).then(console.log)
Promise { <pending> }
> {
transactionHash: '0x3c75df5f355ddf8bcaf578001729fb1307ba948be5411a7d8ea9b151a0c83ec3',
transactionIndex: 0,
blockHash: '0x1704fe4be96ed0a1c2a9cae72671d7612fcf9890bd57ab089d586e23c3ceaa53',
blockNumber: 2,
from: '0x68cd5e5c54e8eeb0bc416ac661ead2cbdf0b843d',
to: '0xf363f0067e127648ae7ade34b7f23cdf3aa91f52',
gasUsed: 26658,
cumulativeGasUsed: 26658,
contractAddress: null,
status: true,
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
events: {}
}

Чтобы подтвердить, что значение было изменено, мы выполняем вызов, чтобы получить значение в состоянии.

> contract.methods.myValue().call().then(console.log)
Promise { <pending> }
> 500

При установке значения он создает обещание в Javascript. После обработки обещания возвращается результат. В этом примере наш результат возвращается через функцию console.log для отображения на экране.

Синопсис

На этом мы завершаем введение во взаимодействие со смарт-контрактами с помощью Web3.js. Для разработчиков это предоставляет библиотеки, необходимые для разработки приложений, которые могут взаимодействовать с блокчейном через смарт-контракты. Разработчики могут использовать стандартный формат JSON, который предоставляет функции, которые они могут использовать для взаимодействия с приложениями на основе блокчейнов. Это упрощает понимание работы между сетью и блокчейном.