Взаимодействие с Ethereum нодой
По сути вся работа с блокчейном в PHP - это так или иначе взаимодействие с блокчейн нодой. Все подписанные транзакции отправляются (бродкастятся) на неё и все данные из блокчейна также можно получить у ноды. Обычно у ноды есть свой json-rpc интерфейс, через который с ней можно взаимодействовать.
Документация по JSON-RPC API Ethereum ноды.
Библиотека
Так как общение с нодой - это просто HTTP-запросы, то у нас есть два варианта. Можно либо использовать готовую библиотеку, которая формирует нужный payload и парсит ответы. Либо использовать любой HTTP-клиент и делать всё вручную. Рассмотрим вариант с уже готовой библиотекой Simple-Web3-Php:
1
composer require drlecks/simple-web3-php
И попробуем подключиться к публичной ноде https://eth.public-rpc.com
и узнать номер текущего блока в блокчейне:
1
2
3
4
use SWeb3\SWeb3;
$node = new SWeb3('https://eth.public-rpc.com');
$res = $node->call('eth_blockNumber', []);
Метод call(string $method, $params = null)
позволяет вызывать json-rpc метод у ноды. В нашем случае вызываем eth_blocknumber, у которого нет параметров. В ответ получим объект stdClass с телом json-rpc ответа:
1
2
3
4
5
6
stdClass Object
(
[id] => 1
[jsonrpc] => 2.0
[result] => 0x14fcf95
)
Нам интересно поле result
, но важно помнить, что данные нода вернет в 16-ом формате. Поэтому, чтобы получить номер блока в читаемом виде - нужно будет явно его привести в 10-ую систему:
1
2
3
4
5
6
7
8
9
use SWeb3\SWeb3;
use SWeb3\Utils;
$node = new SWeb3('https://eth.public-rpc.com');
$res = $node->call('eth_blockNumber', []);
$block = Utils::hexToBn($res->result);
echo 'Block number: ' . $block->toString() . PHP_EOL;
// Block number: 22008077
Получение баланса
Теперь попробуем получить баланс (eth_getBalance()
) какого-нибудь адреса (0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97:
1
2
3
4
5
$res = $node->call('eth_getBalance', ['0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97', 'latest']);
$balance = Utils::hexToBn($res->result);
echo 'Balance: ' . $balance->toString() . PHP_EOL;
// Balance: 16857795621056046838
В результате получаем число, которое отличается от, того что мы видим на эксплорере в ETH BALANCE
:
Почему так происходит? Дело в том, что нода возвращает балансы в wei (наименьший номинал ETH).
1 ETH = 1,000,000,000,000,000,000 WEI.
Чтобы из Wei получить ETH нужно явно привести полученное число wei в eth:
1
2
3
4
5
$res = $node->call('eth_getBalance', ['0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97', 'latest']);
$balance = Utils::hexToBn($res->result);
echo 'Balance: ' . Utils::fromWeiToString($balance, 'ether') . PHP_EOL;
// Balance: 16.857795621056046838
Теперь уже будет больше похоже на правду.
Генерация аккаунта
Мало смысла в работе с блокчейном, не имея своего собственного адреса, поэтому давайте создадим себе адрес (публичный и приватный ключ):
1
2
3
4
5
6
7
8
9
10
use SWeb3\Accounts;
$account = Accounts::create();
echo "Public key: " . $account->publicKey . PHP_EOL;
echo "Private key: " . $account->privateKey . PHP_EOL;
echo "Address: " . $account->address . PHP_EOL;
// Public key: 0x03c484a1c224a35100310228205c40af86a0a511e8ad41ef71470c86b23e25fbfd
// Private key: 0x65e2bda31ccefd2851ef69b268e62a9e00773cfa5506ae5525d3435d4589f2d1
// Address: 0x0e1cd3dc5ceb15f2a515b5cefbcd80ceb935f38d
Теперь попробуем получить баланс нашего адреса и ожидаемо получим 0:
1
2
3
4
5
$res = $node->call('eth_getBalance', [$account->address, 'latest']);
$balance = Utils::hexToBn($res->result);
echo 'Balance: ' . Utils::fromWeiToString($balance, 'ether') . PHP_EOL;
// Balance: 0
После того как научились коннектиться к ноде, понимаем как делать к ней запросы и парсить ответы — можно переходить к более сложным вещам: отправке ETH и взаимодействию со смарт-контрактами.