Я хотел бы получить внутренние транзакции контракта, например: https://etherscan.io/address/0xd654bdd32fc99471455e86c2e7f7d7b6437e9179#internaltx
Я использую веб3 API. Есть ли способ сделать это? Где они появляются в блокчейне?
В настоящее время нет способа сделать это с помощью API web3. Внутренние транзакции, несмотря на название (которое не является частью желтой бумаги; это соглашение, на котором остановились люди), не являются реальными транзакциями и не включены непосредственно в блокчейн; это переводы стоимости, которые были инициированы выполнением контракта.
Таким образом, они нигде не хранятся явным образом: они являются следствием выполнения рассматриваемой транзакции в состоянии блокчейна. Обозреватели блокчейна, такие как etherscan, могут получить их, запустив модифицированный узел с инструментальной EVM, которая записывает все передачи значений, которые происходили как часть выполнения транзакции, сохраняя их отдельно.
В протоколе Ethereum есть только транзакции и вызовы сообщений. Транзакция — это тип вызова сообщения.
Транзакция может выполнять другие вызовы сообщений, но они не являются транзакциями (даже несмотря на то, что обозреватели блокчейна могут ошибочно помечать их как «внутренние транзакции»). Эти (внутренние) вызовы сообщений не публикуются в блокчейне. Чтобы найти внутренние вызовы , транзакцию нужно обработать через EVM (например, https://github.com/ethereumjs/ethereumjs-vm ).
Чтобы попытаться проиллюстрировать, транзакция в Javascript выглядит так:
{
from: ...,
to: "C1",
value: ...,
gas: ...,
data: ...,
gasPrice: ...,
nonce: ...
}
Это то, что вы увидите на блокчейне. Внутренние вызовы — это результат принятия data
части, предоставления ей to
контракта C1 и выполнения виртуальной машины Ethereum. Это data
то, что говорит C1, что он должен вызвать другой контракт C2: {from:C1, to:C2,...}
в блокчейне нет необходимого отдельного объекта.
Кодируется data
в соответствии с ABI, в котором говорится, например, какую функцию следует вызывать и каковы аргументы.
Примечание. С ответом @Nick все передачи значений представляют собой вызов сообщения. Но не все вызовы сообщений являются передачей значений. Передача стоимости — это когда по контракту просто выплачивается некоторое количество Ether/wei (данные равны нулю), но контракты могут вызывать друг друга, не платя друг другу (данные не равны нулю, стоимость равна нулю).
К счастью, у Geth EVM есть новые инструменты для этого. Можно использовать debug_traceTransaction с RPC API.
В NodeJS:
var web3 = require('web3').web3;
web3.currentProvider.sendAsync({
method: "debug_traceTransaction",
params: ['0x3fac854179691e377fc1aa180b71a4033b6bb3bde2a7ef00bc8e78f849ad356e', {}],
jsonrpc: "2.0",
id: "2"
}, function (err, result) {
...
});
Затем вам нужно будет «CREATE», «CALL», «CALLCODE» и «DELEGATECALL» и отслеживать стек. Вы можете прочитать подробное объяснение Ника Джонсона : Instrumenting EVM
Если я наконец реализую это, я напишу полную статью с кодом.
С последними версиями Parity (проверено на юсб 1.8.3
) это тоже возможно. Метод RPC trace_replayTransaction
. Соответствующий код выглядит примерно так
web3.currentProvider.sendAsync({
method: "trace_replayTransaction",
params: [desiredTransactionHash, ['trace']],
jsonrpc: "2.0",
id: "1"
}, function (err, out) {
console.log(out);
}
Документация находится в паритетном репозитории github.
Вы можете использовать callTracer
представленный в geth 1.8 https://github.com/ethereum/go-ethereum/pull/15516
$ nc -U /work/temp/rinkeby/geth.ipc
{"id": 1, "method": "debug_subscribe", "params": ["traceChain", "0x0", "0xffff", {"tracer": "callTracer"}]}
API будет передавать обратно одно уведомление IPC для каждого непустого блока. Исключением является самый последний блок, о котором будет сообщено, даже если он пуст, чтобы пользователь знал, что поток выполнен.
{"jsonrpc":"2.0","id":1,"result":"0xe1deecc4b399e5fd2b2a8abbbc4624e2"}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0x37","hash":"0xdb16f0d4465f2fd79f10ba539b169404a3e026db1be082e7fd6071b4c5f37db7","traces":[{"from":"0x31b98d14007bdee637298086988a0bbd31184523","gas":"0x0","gasUsed":"0x0","input":"0x","output":"0x","time":"1.077µs","to":"0x2ed530faddb7349c1efdbf4410db2de835a004e4","type":"CALL","value":"0xde0b6b3a7640000"}]}}}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0xf43","hash":"0xacb74aa08838896ad60319bce6e07c92edb2f5253080eb3883549ed8f57ea679","traces":[{"from":"0x31b98d14007bdee637298086988a0bbd31184523","gas":"0x0","gasUsed":"0x0","input":"0x","output":"0x","time":"1.568µs","to":"0xbedcf417ff2752d996d2ade98b97a6f0bef4beb9","type":"CALL","value":"0xde0b6b3a7640000"}]}}}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0xf47","hash":"0xea841221179e37ca9cc23424b64201d8805df327c3296a513e9f1fe6faa5ffb3","traces":[{"from":"0xbedcf417ff2752d996d2ade98b97a6f0bef4beb9","gas":"0x4687a0","gasUsed":"0x12e0d","input":"0x6060604052341561000c57fe5b5b6101828061001c6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063230925601461003b575bfe5b341561004357fe5b61008360048080356000191690602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506100c5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000600185858585604051806000526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000866161da5a03f1151561014257fe5b50506020604051035190505b9493505050505600a165627a7a7230582054abc8e7b2d8ea0972823aa9f0df23ecb80ca0b58be9f31b7348d411aaf585be0029","output":"0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063230925601461003b575bfe5b341561004357fe5b61008360048080356000191690602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506100c5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000600185858585604051806000526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000866161da5a03f1151561014257fe5b50506020604051035190505b9493505050505600a165627a7a7230582054abc8e7b2d8ea0972823aa9f0df23ecb80ca0b58be9f31b7348d411aaf585be0029","time":"658.529µs","to":"0x5481c0fe170641bd2e0ff7f04161871829c1902d","type":"CREATE","value":"0x0"}]}}}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0xfff","hash":"0x254ccbc40eeeb183d8da11cf4908529f45d813ef8eefd0fbf8a024317561ac6b"}}}
Трассировка отдельных блоков выполняется параллельно в транзакциях (ограничено числом ядер), а также делает трассировку цепочки параллельной в блоках (ограничено числом ядер).
Для получения информации о внутренних транзакциях вы можете использовать метод debug_traceTransaction. Метод вернет полную трассировку транзакции. По кодам операций и параметрам каждого шага можно получить нужную информацию.
Есть 2 основные проблемы: 1. Выявить принцип работы опкодов, т.к. например, не всегда CALL приводит к внутренней транзакции 2. При большом количестве шагов в трассе ответ может не поместиться в буфер
Вторую проблему можно решить, передав второй параметр методам обработки шагов на стороне geth. Более подробную информацию можно найти здесь - https://github.com/ethereum/go-ethereum/wiki/Management-APIs#debug_tracetransaction
Логику обработки опкодов можно найти здесь https://github.com/Arachnid/etherquery/blob/master/etherquery/trace.go#L102 (для реализации go) или здесь https://github.com/tet32 /etherscanner/blob/master/traceStepFunction.js (для реализации nodejs)
Согласно анонсу версии 1.1 от Parity , вы могли бы сделать это с ним, если перейдете на этот клиент. Цитата:
Новые API-интерфейсы JSONRPC для отслеживания, отслеживания и проверки всех вызовов сообщений и переводов баланса, включая те, которые происходят как «внутренние транзакции»;
Хотя еще не тестировал.
В настоящее время нет возможности сделать это с помощью Web3 API. У вас есть два варианта: (а) запустить узел четности (может быть дорого, и синхронизация может занять до нескольких недель) или (б) использовать отслеживание адресной активности (например, внутренних транзакций) от Alchemy Notify.
Я настоятельно рекомендую использовать Alchemy Notify, это бесплатно, и я запустил его менее чем за 5 минут. Вот ссылка на их документы: https://docs.alchemyapi.io/alchemy/guides/using-webhooks#address-activity .
Удачи!
В то время как внутренние транзакции имеют реальные последствия для остатков на счетах, удивительно, что сами внутренние транзакции не хранятся в сети. Чтобы увидеть внутренние транзакции, вы должны запустить транзакцию и отследить вызовы, которые она делает. В то время как некоторые контракты регистрируют события в цепочке, которые регистрируют внутреннюю активность, многие этого не делают, потому что для этого требуется дополнительный газ.
^ из блога Blocknative.com — https://blog.blocknative.com/blog/eth-internal-transactions
Их система уведомлений теперь поддерживает внутренние транзакции. Вы можете получить обновление через их API, когда ваш кошелек или контракт участвует во внутренней транзакции.
Используя API Etherscan, вы можете выполнить эту работу.
Для получения дополнительной информации о концепции см. этот подробный ответ .
Простой способ сделать это — выяснить, в каком блоке произошла транзакция. Зная, что вы делаете вызов web3 к полному заархивированному узлу. web3.eth.getBalance(address, block)
чем вычесть 1 блок и сделать это снова. Вычтите разницу, и вот ваше значение.
Я думаю, вы просто смотрите журналы транзакций. Если есть «внутренняя транзакция», эта транзакция должна быть одним из журналов в объекте квитанции транзакции. Но я могу ошибаться. @vitalikbuterin
Если вы знаете блок транзакции, вы можете узнать переданную стоимость:
let tx;
const txs = await web3.eth.getPastLogs({
fromBlock: block,
toBlock: block,
address: contractAddress
});
if(txs){
for(let i=0;i<txs.length;i++){
const tx_ = await web3.eth.getTransaction(txs[i].transactionHash);
if(tx_ && tx_.from === from){
tx = tx_;
break;
}
}
}
Чтобы получить значение, вы вызываете:tx.value
Пол С
Пабло Ябо
Пол С
Тьяден Хесс
address.send()
илиaddress.call()
в Solidity .Пабло Ябо