Видно ли значение параметра метода контракта в блокчейне? На Etherscan в информации о tx есть поле «Входные данные», в котором говорится:
Двоичные данные, которые сформировали вход транзакции, либо входные данные, если это был вызов сообщения, либо инициализация контракта, если это было создание контракта.
Это то, что я ищу?
Да, эта информация общедоступна и генерируется следующим образом:
Освоение Ethereum — передача полезной нагрузки данных в EOA или контракт
Когда ваша транзакция содержит данные, она, скорее всего, адресована контрактному адресу. Это не означает, что вы не можете отправить полезную нагрузку данных в EOA — это полностью допустимо в протоколе Ethereum. Однако в этом случае интерпретация данных зависит от кошелька, который вы используете для доступа к EOA. Он игнорируется протоколом Ethereum. Большинство кошельков также игнорируют любые данные, полученные в транзакции с EOA, который они контролируют. Возможно, в будущем появятся стандарты, которые позволят кошелькам интерпретировать данные так же, как это делают контракты, что позволит транзакциям вызывать функции, работающие внутри пользовательских кошельков. Критическое отличие заключается в том, что любая интерпретация полезной нагрузки данных EOA не регулируется правилами консенсуса Ethereum, в отличие от исполнения контракта.
А пока предположим, что ваша транзакция доставляет данные на адрес контракта. В этом случае данные будут интерпретироваться EVM как вызов контракта. Большинство контрактов используют эти данные более конкретно как вызов функции, вызывая именованную функцию и передавая ей любые закодированные аргументы.
Полезная нагрузка данных, отправляемая в ABI-совместимый контракт (которым, как вы можете предположить, являются все контракты), представляет собой шестнадцатеричное сериализованное кодирование:
Селектор функций
Первые 4 байта хэша Keccak-256 прототипа функции. Это позволяет контракту однозначно определить, какую функцию вы хотите вызвать.
Аргументы функции
Аргументы функции, закодированные в соответствии с правилами для различных элементарных типов, определенных в спецификации ABI.
В solidity_faucet_example мы определили функцию для снятия средств:
function withdraw(uint withdraw_amount) public {
Прототип функции определяется как строка, содержащая имя функции, за которой следуют типы данных каждого из ее аргументов, заключенные в круглые скобки и разделенные запятыми. Имя функции здесь — remove, и она принимает единственный аргумент — uint (который является псевдонимом для uint256), поэтому прототипом remove будет:
withdraw(uint256)
Давайте посчитаем хэш Keccak-256 этой строки:
> web3.sha3("withdraw(uint256)"); '0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f'
Первые 4 байта хеша — 0x2e1a7d4d. Это значение нашего «селектора функций», которое сообщит контракту, какую функцию мы хотим вызвать.
Далее давайте вычислим значение, которое будет передано в качестве аргумента remove_amount. Хотим вывести 0.01 эфира. Давайте закодируем это в шестнадцатеричное сериализованное 256-битное целое число без знака с обратным порядком байтов, выраженное в wei:
> withdraw_amount = web3.toWei(0.01, "ether"); '10000000000000000' > withdraw_amount_hex = web3.toHex(withdraw_amount); '0x2386f26fc10000'
Теперь мы добавляем селектор функций к количеству (дополненному до 32 байт):
2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000
Это полезная нагрузка данных для нашей транзакции, вызывающая функцию снятия и запрашивающая 0,01 эфира в качестве суммы снятия.