如何获取交易(不是合约)的所有事件?
How to get all events for a transaction (not contract)?
我想使用 web3 获取 Solidity 合约发出的所有事件,但是 .getPastEvents() 方法适用于合约。
这 returns contractInstance 的所有事件,但是,我的合约调用其他也发出事件的合约。
await contractInstance.getPastEvents("allEvents", {fromBlock: bn, toBlock: bn});
我想从交易中获取所有事件,而不是从合约中获取。
或者作为替代方案,甚至是来自一个块的所有事件,然后我可以使用交易哈希过滤掉这些事件,以获得我想要的。是否有 returns 块中所有事件的函数?我已经看过,但找不到。我必须知道链中的每个合同并分别获取事件吗?或许吧。
我做了一个非常简单的例子来说明。
solidity代码:
pragma solidity 0.5.8;
contract contractA {
event eventA();
function methodA( address b ) public {
emit eventA();
contractB instanceB = contractB( b );
instanceB.methodB();
}
}
contract contractB {
event eventB();
function methodB() public {
emit eventB();
}
}
我正在使用 Truffle 来简化它。这是迁移文件:
var contractA = artifacts.require("contractA");
var contractB = artifacts.require("contractB");
module.exports = function(deployer) {
deployer.deploy(contractA);
deployer.deploy(contractB);
这是 truffle javascript 代码,它调用发出事件 A 的 contractA 方法 A,并调用发出事件 B 的 contractB 方法 B:
const contractA = artifacts.require("contractA");
const contractB = artifacts.require("contractB");
contract("contractA", async accounts => {
thisAccount = accounts[0];
it( "Simple test", async () => {
const instanceA = await contractA.deployed();
const instanceB = await contractB.deployed();
const transaction = await instanceA.methodA( instanceB.address, { from: thisAccount } );
const bn = transaction.receipt.blockNumber, txHash = transaction.tx;
const allEventsA = await instanceA.getPastEvents("allEvents", {fromBlock: bn, toBlock: bn});
const allEventsB = await instanceB.getPastEvents("allEvents", {fromBlock: bn, toBlock: bn});
console.log("A");
console.log( allEventsA );
console.log("B");
console.log( allEventsB );
});
});
这是输出:
$ truffle test test.js
Using network 'development'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Contract: contractA
A
[
{
logIndex: 0,
transactionIndex: 0,
transactionHash: '0xe99db12863e5c0a0ae2c9c603d9d29f46a74d45ee9bf9f56d15f6f7bd1888058',
blockHash: '0xfa65496b8cb6ecf5b729892836adf80aa883e6823bbdb2d1b8cdfe61b5c97256',
blockNumber: 1573,
address: '0x97519Ada953F882d61625125D5D68E7932250E9F',
type: 'mined',
id: 'log_d28138a2',
returnValues: Result {},
event: 'eventA',
signature: '0x72f2637d8047e961ba6b558fdf63d428e9734bdf7ee2fb2b114f3b1aa65335c7',
raw: { data: '0x', topics: [Array] },
args: Result { __length__: 0 }
}
]
B
[
{
logIndex: 1,
transactionIndex: 0,
transactionHash: '0xe99db12863e5c0a0ae2c9c603d9d29f46a74d45ee9bf9f56d15f6f7bd1888058',
blockHash: '0xfa65496b8cb6ecf5b729892836adf80aa883e6823bbdb2d1b8cdfe61b5c97256',
blockNumber: 1573,
address: '0x00108B6A5572d95Da87e8b4bbF1A3DcA2a565ff7',
type: 'mined',
id: 'log_da38637d',
returnValues: Result {},
event: 'eventB',
signature: '0x34a286cd617cdbf745989ac7e8dab3f95e8bb2501bcc48d9b6534b73d055a89c',
raw: { data: '0x', topics: [Array] },
args: Result { __length__: 0 }
}
]
✓ Simple test (76ms)
如您所见,我必须独立调用每份合同。我想知道是否有一种 "transaction object" 方法可以在一次调用中获取这两个事件 - 因为它们毕竟来自同一笔交易。
您可以想象在同一交易中从多个合约发出事件的情况。
也许这是不可能的,但我想我还是会问的。
调用 instanceA.methodA()
触发的交易称为 内部交易,当您尝试获取事件时,它们的事件不包括在内。
有一种方法可以从一个交易中获取所有事件,但是有点麻烦:
1 - 使用 web3.eth.getTransactionReceipt()
获取 TX 收据。这为您提供了包含事件对象的日志数组,其中包含三个重要字段:address
、data
和 topics
.
address
,触发事件的合约地址。
data
、non-indexed 个事件参数。
topics
,事件签名的哈希值和索引参数的哈希值(如果有的话)
2 - 有了这些信息,使用 address
获得合同 abi。现在你有了这个合约可以触发的所有事件的列表,因为你是 abi。散列所有事件签名并找到与 topics
数组中的第一项匹配的签名。您可以使用 web3.eth.abi.encodeEventSignature()
检查事件签名的哈希值。这样你就会找到它是哪个事件。还有参数名称。
3 - 使用带有 web3.eth.abi.decodeLog(inputs, hexString, topics)
的事件签名解码 abi
示例:web3.eth.abi.decodeLog([{
type: 'string',
name: 'myString'
},{
type: 'uint256',
name: 'myNumber',
indexed: true
},{
type: 'uint8',
name: 'mySmallNumber',
indexed: true
}],
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000748656c6c6f252100000000000000000000000000000000000000000000000000',
['0x000000000000000000000000000000000000000000000000000000000000f310', '0x0000000000000000000000000000000000000000000000000000000000000010']);
你得到:
Result {
'0': 'Hello%!',
'1': '62224',
'2': '16',
myString: 'Hello%!',
myNumber: '62224',
mySmallNumber: '16'
这里也有解释:https://codeburst.io/deep-dive-into-ethereum-logs-a8d2047c7371
我想使用 web3 获取 Solidity 合约发出的所有事件,但是 .getPastEvents() 方法适用于合约。
这 returns contractInstance 的所有事件,但是,我的合约调用其他也发出事件的合约。
await contractInstance.getPastEvents("allEvents", {fromBlock: bn, toBlock: bn});
我想从交易中获取所有事件,而不是从合约中获取。
或者作为替代方案,甚至是来自一个块的所有事件,然后我可以使用交易哈希过滤掉这些事件,以获得我想要的。是否有 returns 块中所有事件的函数?我已经看过,但找不到。我必须知道链中的每个合同并分别获取事件吗?或许吧。
我做了一个非常简单的例子来说明。
solidity代码:
pragma solidity 0.5.8;
contract contractA {
event eventA();
function methodA( address b ) public {
emit eventA();
contractB instanceB = contractB( b );
instanceB.methodB();
}
}
contract contractB {
event eventB();
function methodB() public {
emit eventB();
}
}
我正在使用 Truffle 来简化它。这是迁移文件:
var contractA = artifacts.require("contractA");
var contractB = artifacts.require("contractB");
module.exports = function(deployer) {
deployer.deploy(contractA);
deployer.deploy(contractB);
这是 truffle javascript 代码,它调用发出事件 A 的 contractA 方法 A,并调用发出事件 B 的 contractB 方法 B:
const contractA = artifacts.require("contractA");
const contractB = artifacts.require("contractB");
contract("contractA", async accounts => {
thisAccount = accounts[0];
it( "Simple test", async () => {
const instanceA = await contractA.deployed();
const instanceB = await contractB.deployed();
const transaction = await instanceA.methodA( instanceB.address, { from: thisAccount } );
const bn = transaction.receipt.blockNumber, txHash = transaction.tx;
const allEventsA = await instanceA.getPastEvents("allEvents", {fromBlock: bn, toBlock: bn});
const allEventsB = await instanceB.getPastEvents("allEvents", {fromBlock: bn, toBlock: bn});
console.log("A");
console.log( allEventsA );
console.log("B");
console.log( allEventsB );
});
});
这是输出:
$ truffle test test.js
Using network 'development'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Contract: contractA
A
[
{
logIndex: 0,
transactionIndex: 0,
transactionHash: '0xe99db12863e5c0a0ae2c9c603d9d29f46a74d45ee9bf9f56d15f6f7bd1888058',
blockHash: '0xfa65496b8cb6ecf5b729892836adf80aa883e6823bbdb2d1b8cdfe61b5c97256',
blockNumber: 1573,
address: '0x97519Ada953F882d61625125D5D68E7932250E9F',
type: 'mined',
id: 'log_d28138a2',
returnValues: Result {},
event: 'eventA',
signature: '0x72f2637d8047e961ba6b558fdf63d428e9734bdf7ee2fb2b114f3b1aa65335c7',
raw: { data: '0x', topics: [Array] },
args: Result { __length__: 0 }
}
]
B
[
{
logIndex: 1,
transactionIndex: 0,
transactionHash: '0xe99db12863e5c0a0ae2c9c603d9d29f46a74d45ee9bf9f56d15f6f7bd1888058',
blockHash: '0xfa65496b8cb6ecf5b729892836adf80aa883e6823bbdb2d1b8cdfe61b5c97256',
blockNumber: 1573,
address: '0x00108B6A5572d95Da87e8b4bbF1A3DcA2a565ff7',
type: 'mined',
id: 'log_da38637d',
returnValues: Result {},
event: 'eventB',
signature: '0x34a286cd617cdbf745989ac7e8dab3f95e8bb2501bcc48d9b6534b73d055a89c',
raw: { data: '0x', topics: [Array] },
args: Result { __length__: 0 }
}
]
✓ Simple test (76ms)
如您所见,我必须独立调用每份合同。我想知道是否有一种 "transaction object" 方法可以在一次调用中获取这两个事件 - 因为它们毕竟来自同一笔交易。
您可以想象在同一交易中从多个合约发出事件的情况。
也许这是不可能的,但我想我还是会问的。
调用 instanceA.methodA()
触发的交易称为 内部交易,当您尝试获取事件时,它们的事件不包括在内。
有一种方法可以从一个交易中获取所有事件,但是有点麻烦:
1 - 使用 web3.eth.getTransactionReceipt()
获取 TX 收据。这为您提供了包含事件对象的日志数组,其中包含三个重要字段:address
、data
和 topics
.
address
,触发事件的合约地址。data
、non-indexed 个事件参数。topics
,事件签名的哈希值和索引参数的哈希值(如果有的话)
2 - 有了这些信息,使用 address
获得合同 abi。现在你有了这个合约可以触发的所有事件的列表,因为你是 abi。散列所有事件签名并找到与 topics
数组中的第一项匹配的签名。您可以使用 web3.eth.abi.encodeEventSignature()
检查事件签名的哈希值。这样你就会找到它是哪个事件。还有参数名称。
3 - 使用带有 web3.eth.abi.decodeLog(inputs, hexString, topics)
示例:web3.eth.abi.decodeLog([{
type: 'string',
name: 'myString'
},{
type: 'uint256',
name: 'myNumber',
indexed: true
},{
type: 'uint8',
name: 'mySmallNumber',
indexed: true
}],
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000748656c6c6f252100000000000000000000000000000000000000000000000000',
['0x000000000000000000000000000000000000000000000000000000000000f310', '0x0000000000000000000000000000000000000000000000000000000000000010']);
你得到:
Result { '0': 'Hello%!', '1': '62224', '2': '16', myString: 'Hello%!', myNumber: '62224', mySmallNumber: '16'
这里也有解释:https://codeburst.io/deep-dive-into-ethereum-logs-a8d2047c7371