Как получить внутренние транзакции контракта

Я хотел бы получить внутренние транзакции контракта, например: https://etherscan.io/address/0xd654bdd32fc99471455e86c2e7f7d7b6437e9179#internaltx

Я использую веб3 API. Есть ли способ сделать это? Где они появляются в блокчейне?

надеюсь, ответ объяснит, что такое внутренняя транзакция
Это транзакции, инициированные контрактами.
уверен, но все еще не уверен, что это значит. Я не помню ключевого слова солидности для этого. ссылка на сайт?
@PaulS Это любая транзакция, отправленная через функции address.send()или address.call()в Solidity .
Нет, есть и другие способы «отправить» эфир, например, суицид() или при создании нового контракта.

Ответы (13)

В настоящее время нет способа сделать это с помощью API web3. Внутренние транзакции, несмотря на название (которое не является частью желтой бумаги; это соглашение, на котором остановились люди), не являются реальными транзакциями и не включены непосредственно в блокчейн; это переводы стоимости, которые были инициированы выполнением контракта.

Таким образом, они нигде не хранятся явным образом: они являются следствием выполнения рассматриваемой транзакции в состоянии блокчейна. Обозреватели блокчейна, такие как etherscan, могут получить их, запустив модифицированный узел с инструментальной EVM, которая записывает все передачи значений, которые происходили как часть выполнения транзакции, сохраняя их отдельно.

Понятно! Знаете ли вы, есть ли план добавить какой-то механизм для получения этих транзакций, или я должен создать инструментальную EVM.
Я не знаю о текущей работе по добавлению подобного API, хотя она может быть; если ваша цель состоит в том, чтобы получить внутренние переводы для данной транзакции, это было бы практично. Однако, если ваша цель — получить все переводы на счет, этого недостаточно — и для этого есть ошибка .
У меня уже есть список транзакций для внеконтрактных транзакций, но я хотел бы добавить «внутренние транзакции» в список транзакций. Как вы думаете, инструментальный EVM может работать для этого?
@PabloYabo Так бы и было, но если вас волнуют «все транзакции на эту учетную запись», вам придется проводить через нее каждую транзакцию на случай, если она произвела перевод на интересующую вас учетную запись. Если вам нужны «все передачи значений, инициированные этой транзакцией», вы можете запустить ее только для этой транзакции.
Идея состоит в том, чтобы иметь базу данных со всеми транзакциями всех учетных записей, поэтому в этой схеме возможно выполнение всех транзакций. Теперь мы получаем все блоки, транзакции и квитанции.
@PabloYabo В этом случае такой гипотетический API, вероятно, послужит вашим целям, но пока вам придется самостоятельно настроить EVM.
@PabloYabo, пожалуйста, объясните, как вам удалось получить список tx для неконтрактных транзакций ?

В протоколе 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 (данные равны нулю), но контракты могут вызывать друг друга, не платя друг другу (данные не равны нулю, стоимость равна нулю).

Можно ли получить все эти журналы?
Да, выполнение EVM включает все коды операций LOG.

К счастью, у 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

Если я наконец реализую это, я напишу полную статью с кодом.

Проблема здесь в том, что любой контракт может вызывать интересующий вас контракт в любое время — если вы хотите, чтобы каждая внутренняя транзакция отправлялась в ваш контракт, единственный способ сделать это — найти следы каждой транзакции, которая произошла с тех пор. ваш контракт был развернут. Один полукраткий путь заключается в фильтрации событий, но при этом игнорируются «внутренние транзакции», которые не генерируют события. Пару дней назад я разместил здесь код на C++: github.com/Great-Hill-Corporation/ethrpc .
Да, я знаю, это был просто пример. Затем вам нужно будет сделать то же самое для каждой транзакции. Моя идея состоит в том, чтобы проиндексировать все, а затем поместить информацию в базу данных.
Я работаю над той же самой идеей. Все проиндексируйте и поместите в базу данных. Проблема, которую я вижу в этом, заключается в том, что это централизует эти данные. Если я создам эти данные, как я узнаю, что я их не подделал? Я пытался найти способ как индексировать его, так и децентрализовать «расчет индексации». Я знаю, как децентрализовать хранилище (IPFS), но не знаю, как децентрализовать расчет индексации. У вас есть какие-нибудь мысли по этому поводу? У вас есть гитхаб, который я могу проверить? Мое очень грубое начало находится на github.com/Great-Hill-Corporation/ethrpc . Возможно, Golem позволяет децентрализовать расчет.
Почему существует web3.web3, а не только web3. ?

С последними версиями 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"}}}

Трассировка отдельных блоков выполняется параллельно в транзакциях (ограничено числом ядер), а также делает трассировку цепочки параллельной в блоках (ограничено числом ядер).

Так как же идентифицировать передачу значения для ERC-20 в этом потоке?

Для получения информации о внутренних транзакциях вы можете использовать метод 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 для отслеживания, отслеживания и проверки всех вызовов сообщений и переводов баланса, включая те, которые происходят как «внутренние транзакции»;

Хотя еще не тестировал.

Это выглядит интересно, но не удалось найти хорошо документированный пример, хотя в часто задаваемых вопросах по четности упоминается вики-страница для него. Опубликовано на github как проблема четности № 1969.
@Paul: теперь это дает 404, он был перенесен куда-то еще?

В настоящее время нет возможности сделать это с помощью Web3 API. У вас есть два варианта: (а) запустить узел четности (может быть дорого, и синхронизация может занять до нескольких недель) или (б) использовать отслеживание адресной активности (например, внутренних транзакций) от Alchemy Notify.

Я настоятельно рекомендую использовать Alchemy Notify, это бесплатно, и я запустил его менее чем за 5 минут. Вот ссылка на их документы: https://docs.alchemyapi.io/alchemy/guides/using-webhooks#address-activity .

Удачи!

веб-хуки уведомлений потрясающие 💙
+1 к этим веб-перехватчикам уведомлений

В то время как внутренние транзакции имеют реальные последствия для остатков на счетах, удивительно, что сами внутренние транзакции не хранятся в сети. Чтобы увидеть внутренние транзакции, вы должны запустить транзакцию и отследить вызовы, которые она делает. В то время как некоторые контракты регистрируют события в цепочке, которые регистрируют внутреннюю активность, многие этого не делают, потому что для этого требуется дополнительный газ.

^ из блога Blocknative.com — https://blog.blocknative.com/blog/eth-internal-transactions

Их система уведомлений теперь поддерживает внутренние транзакции. Вы можете получить обновление через их API, когда ваш кошелек или контракт участвует во внутренней транзакции.

По состоянию на 20.05.2021 он недоступен в BSC, только в основной сети Ethereum.

Используя 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