web3js — декодировать входные данные транзакции
У меня есть ABI и значение ввода
транзакции, и я хочу знать, какая функция была вызвана в контракте и с какими аргументами (один или несколько разных типов), предпочтительно используя geth
, JSON-RPC
и некоторый псевдокод, который я затем могу перевести на Ruby.
На SO есть пара похожих вопросов, но ни один из них не ответил на вопрос так, чтобы он был понятен новичку в Ethereum.
В качестве примера я использую контракт MetaCoin
, сгенерированный Truffle. Я вызываю метод getBalance('0xfd46f749f9d916122fe958d7f8d5ad033b187472')
и получаю ввод 0xf8b2cb4f00000000000000000000000000fd46f749f9d916 122fe958d7f8d5ad033b187472
.
трюфель (разработка) > web3.eth.getTransaction('0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff') {хэш: '0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff', одноразовый номер: 5, блокхеш: '0xd150b520eb69а621а7218722c0de5b270c9abc499a90a81ca96340e274599c28', номер блока: 6, индекс транзакции: 0, от: '0xfd46f749f9d916122fe958d7f8d5ad033b187472', на: '0x8dec2f9cccbe718c7c51e9154f223eb226bb7942', значение: { [Строка: '0'] s: 1, e: 0, c: [0]}, газ: 4712388, gasPrice: { [Строка: '100000000000'] s: 1, e: 11, c: [100000000000]}, ввод: '0xf8b2cb4f0000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472' }
ABI выглядит следующим образом:
[ { "константа": ложь, "входы": [ { "имя": "адрес", "тип": "адрес" } ], "имя": "getBalanceInEth", "выход": [ { "имя": "", "тип": "uint256" } ], «подлежит оплате»: ложь, "тип": "функция" }, { "константа": ложь, "входы": [ { "имя": "получатель", "тип": "адрес" }, { "имя": "количество", "тип": "uint256" } ], "имя": "sendCoin", "выход": [ { "имя": "достаточно", "тип": "логическое" } ], «подлежит оплате»: ложь, "тип": "функция" }, { "константа": ложь, "входы": [ { "имя": "адрес", "тип": "адрес" } ], "имя": "получить баланс", "выход": [ { "имя": "", "тип": "uint256" } ], «подлежит оплате»: ложь, "тип": "функция" }, { "входы": [], «подлежит оплате»: ложь, "тип": "конструктор" }, { "анонимно": ложь, "входы": [ { "индексировано": правда, "имя": "_от", "тип": "адрес" }, { "индексировано": правда, "имя": "_к", "тип": "адрес" }, { "индексировано": ложь, "имя": "_значение", "тип": "uint256" } ], "имя": "Перевод", "тип": "событие" } ]
Как я могу декодировать любой ввод, чтобы узнать, какой метод был вызван и какие аргументы были переданы?
Обновление
Добавил в логи все данные блока с полем ввода в самом низу.
{"число"=>"0x09", "хэш" => "0xf543eba0c80d49beea1f934c0f0ad9f0babe272a8318312545d43e6b612e4006", "родительский хэш" => "0xde7a61e8dd84b5e080da8e16430951f7f138347c77ed263d0093e367c9d30775", "одноразовый номер" => "0x0", "sha3Uncles"=> "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948а7413ф0а142фд40д49347", "журналыБлум"=> "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000", "Корень транзакций"=> "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "государственный корень" => "0x269cfa04ca1fe73202f788397ece62c520c64d5da7225ba2af2d673a2e9892f2", "receipRoot"=> "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "майнер"=>"0x000000000000000000000000000000000000000000000000000000000000000000000000000, "сложность"=>"0x0", "totalDifficulty"=>"0x0", "дополнительные данные"=>"0x0", "размер" => "0x03e8", "gasLimit"=>"0x47e7c4", "использованный газ"=>"0x5a3e", "отметка времени" => "0x58c83fda", "транзакции" => [{"хеш"=> "0xce1eaf03dd1dfa5898243711ebcc1dc5c6357701f5a6c19f0b1f84130cb651fa", "одноразовый номер" => "0x08", "блокхэш" => "0xf543eba0c80d49beea1f934c0f0ad9f0babe272a8318312545d43e6b612e4006", "номер_блока"=>"0x09", "индекс транзакции"=>"0x0", "из" => "0xfd46f749f9d916122fe958d7f8d5ad033b187472", "к" => "0x8dec2f9cccbe718c7c51e9154f223eb226bb7942", "значение" => "0x0", "газ"=>"0x47e7c4", "Цена газа"=>"0x174876e800", "ввод" => "0xf8b2cb4f0000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472"}], "дяди"=>[]}
Декодирование входных данных транзакции Ethereum с помощью Python
Декодирование входных данных с помощью Python
Опубликовано в·
4 мин чтения·
24 июня 2021 г. 90 009Если вы делаете первые шаги в качестве блокчейна Инженер, отличным местом для начала может стать создание приложения, которое декодирует транзакции, в частности входные данные. Расшифровка входных данных является ключом к пониманию того, что на самом деле имело место в транзакции. Например, взгляните на эту транзакцию ниже.
Вы можете видеть, что он содержит высокоуровневую информацию о транзакции, включая адреса туда и обратно, использованный газ, стоимость транзакции, компоненты подписи и многое другое. Но что на самом деле произошло в этой сделке? Какие токены были обменены? Чей смарт-контракт использовался? Чтобы по-настоящему понять детали, нам нужно расшифровать входных данных .
Входные данные… что это?
Прежде чем мы перейдем к коду, давайте рассмотрим входные данные и то, как они используются в блокчейне. Мы будем использовать транзакцию, показанную выше, в качестве нашего примера.
Когда мы ищем транзакцию на Etherscan, мы видим, что кто-то отправил 4. 195472736637743549 ETH
на смарт-контракт SushiSwap в обмен на токена 20 BOR
. Пользователь, вероятно, инициировал транзакцию в пользовательском интерфейсе SushiSwap, что привело к выполнению транзакции смарт-контрактом. Но откуда смарт-контракт знал, что делать? Как вы уже догадались — входные данные.
Входные данные описаны ethereum.org как дополнительная информация, необходимая для транзакции . Структура этой информации зависит от того, какой тип транзакции имеет место. Если транзакция представляет собой вызов сообщения
(подписанный внешней учетной записью (EOA) или из смарт-контракта в EOA), входные данные содержат информацию, необходимую для правильного выполнения функции смарт-контракта. Если это транзакция создания контракта , то входные данные будут содержать байт-код контракта и любые закодированные аргументы, требуемые конструктором. Если транзакция
перевод средств
между двумя EOA, входные данные будут пустыми, так как дополнительная информация не требуется.
В нашем примере транзакция представляет собой вызов сообщения
, поскольку мы вызываем функцию в развернутом смарт-контракте. The input data looks like this:
0x8803dbee000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000003a4837fc5242c4ec00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000009a7ed54b8c2c5816c1800476f5111a1e886575020000000000000000000000000000000000000000000000000000000000000000000000000000000000060cfee3f00000000000000000000000 00000000000000000000000000000000000000000200000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000 000003c9d6c1c73b31c837832c72e04d3152f051fc1a9
Это шестнадцатеричное значение используется смарт-контрактом, чтобы определить, какую функцию ему необходимо выполнить, и какие аргументы необходимы для обеспечения выполнения функции так, как задумано пользователем SushiSwap. При декодировании вы получаете определение функции:
swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] путь, адрес до, uint256 крайний срок)
И его аргументы:
amountOut : 2000000000000000000 00
amountInMax : 4199668209374381292
путь : 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, 0x3c9d6c1C73b 31c837832c72E04D3152f051fc1A9
to : 0x9A7eD54b8c2c5816C1800476F5111A1e88657502
крайний срок : 1624239679
Но как мы можем использовать Python для преобразования этого шестнадцатеричного ввода в обычный текст? Разберем код.
Декодирование входных данных
Мы будем использовать библиотеку Web3 для взаимодействия с узлом Ethereum. Требования по установке и началу работы см. в документации по Web3.
Наш первый шаг — получить сводку транзакций, передав хэш транзакции методу get_transaction() Web3 . Это возвращает словарь, содержащий соответствующую информацию для нашей транзакции, как показано в начале этой статьи.
Далее нам нужно получить Application Binary Interface (ABI) смарт-контракта. Это позволяет нам создать Объект контракта , который мы используем для взаимодействия со смарт-контрактом. Мы можем сделать это, вызвав Etherscan API. Вам понадобится ключ API Etherscan, и вы можете получить его бесплатно, настроив учетную запись на странице разработчика Etherscan.
Обратите внимание, что мы используем значение от до
из нашей транзакции в качестве адреса смарт-контракта. Для транзакций, которые вызывают функцию смарт-контракта, адресом смарт-контракта всегда будет адрес транзакции от до
.
Далее мы создадим наш объект контракта , передав адрес смарт-контракта и ABI в качестве аргументов методу
Возвращаемый объект содержит множество полезных методов и свойств, которые мы можем использовать для взаимодействия с нашим смарт-контрактом. contract()
.
Когда у нас есть объект Contract , мы используем метод decode_function_input()
для декодирования нашего ввода.
И бац! Мы сделали это. Метод возвращает кортеж, который мы можем распаковать в два объекта.
— это экземпляр функции смарт-контракта, используемой нашей транзакцией.
swapTokensForExactTokens(unit256,united256,address[],unit256)
Этот объект включает в себя ABI смарт-контракта, имя функции, инструмент оценки газа и другие методы и свойства, которые мы можно использовать для создания и вызова новых транзакций.
func_params
— это словарь, содержащий параметры транзакции в виде ключей и аргументы в виде значений.