Take a look at web3.eth.filter and watch
.
Something like this:
const filter = web3.eth.filter({
fromBlock: 0,
toBlock: 'latest',
address: contractAddress,
topics: [web3.sha3('newtest(string,uint256,string,string,uint256)')]
})
filter.watch((error, result) => {
//
})
Note the part that "In Solidity: The first topic is the hash of the signature of the event." Canonical types, such as uint256
have to be used in signatures.
EDIT: Per @plingamp's comment web3.sha3
now includes the '0x'.
I will try to anwser your question. I worked on bloom filters in cpp-ethereum and Parity.
will retrieving event logs become prohibitively slow as the blockchain becomes larger?
Not necessarily. Everything depends on the implementation, logs density (average number of logs / block) and number of cache levels.
More specifically, what is the time complexity of eth_getLogs
?
In worst case, where every block contains log matching your query it is 0(n). But it's rarely a case. Bloom filters utilize probability of false positives, so the more sophisticated your filter is (more topics it has), the faster you will get your results.
Is eth_getLogs even the correct RPC request for what I'm trying to do?
Yes
To summarise, I believe, that 10s response time is caused by sub-optimal imlementation of bloom filters in go-ethereum. Here are the results of benchmarks with parity:
Find all logs from block 0 to 986082 with address: 0x33990122638b9132ca29c723bdf037f1a891a70c (should return 1602 logs).
time curl -X POST --data '{"id":8,"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x0","toBlock":"0xf0be2", "address": "0x33990122638b9132ca29c723bdf037f1a891a70c"}]}' -H "Content-Type: application/json" http://127.0.0.1:3030 >> /dev/null
geth first request:
real 0m17.003s
geth second request (I assumed, that results should be cached after the first one).
real 0m18.023s
parity first request (~24x faster then geth)
real 0m0.770s
parity second request (~30x faster then geth)
real 0m0.668s
The gap between Parity and geth closes dramatically when there are no logs to be found:
Find all logs from block 0 to 986082 with address: 0x33990122638b9132ca29c723bdf037f1a891a70d (address does not exist, 0 logs returned).
time curl -X POST --data '{"id":8,"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x0","toBlock":"0xf0be2", "address": "0x33990122638b9132ca29c723bdf037f1a891a70d"}]}' -H "Content-Type: application/json" http://127.0.0.1:3030 >> /dev/null
geth first request:
real 0m0.022s
geth second request
real 0m0.021s
parity first request (4x slower than geth)
real 0m0.080s
parity second request (1.5x slower than geth)
real 0m0.030s
Best Answer
Typically you would first create a new filter (
eth_newFilter
+eth_getFilterLogs
) and reuse that filter to perform the same query many times as well as listen for changes. However, you can also install an ad-hoc filter witheth_getLogs
, referencing the topics you wish to search over.A topic is a piece of data you are searching. For example, if you have the following event:
The following filter would search for all logs going to
0xb3904758c0d3bfc25746c47caa45b01da8930e19
:This filter would search for all logs coming from
0xb3904758c0d3bfc25746c47caa45b01da8930e19
:And this filter would search for all logs going to
0xb3904758c0d3bfc25746c47caa45b01da8930e19
from0x8cc19c7b50857abbfbeeed31c302319a075d4a9b
:A full golang wrapper for RPC requests would look something like this:
The
EthereumClient
can be instantiated in a different package by something like this:This
client
can now be used to start a new filter and get the logs from that filter.I don't have a specific example for this use case, but please see this for some examples of making RPC requests in Go.