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. на смарт-контракт SushiSwap в обмен на
195472736637743549 ETH токена 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 — это словарь, содержащий параметры транзакции в виде ключей и аргументы в виде значений.
