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
Topics are indexed parameters to an event.
topic[0]
always refers to the hash of the hash of the event itself, and can have up to 3 indexed arguments, which will each be reflected in the topics.
EVM uses low-level primitives called logs to map them to high-level Solidity construct called Event. Logs may contain different topics that are indexed arguments.
Consider Event:
event PersonCreated(uint indexed age, uint height);
And you fire it the foobar
function of MyContract
:
function foobar() {
emit PersonCreated(26, 176);
}
This will create a low-level EVM log entry with topics
0x6be15e8568869b1e100750dd5079151b32637268ec08d199b318b793181b8a7d (Keccak-256 hash of PersonCreated(uint256,uint256)
)
0x36383cc9cfbf1dc87c78c2529ae2fcd4e3fc4e575e154b357ae3a8b2739113cf (Keccak-256 hash of age
), value 26
You'll notice that height will not be a topic, but it will be included in the data section of the event.
Internally, your Ethereum node (Geth / Parity) will index arguments to build on indexable search indexes, so that you can easily do look ups by value later. Because creating indexes takes additional disk space, indexed parameters in events have additional gas cost. However, indexed are required to any meaningful look up in scale of events by value later.
Now in the web3 client you want to watch for creation events of all persons that are age
of 26, you can simply do:
var createdEvent = myContract.PersonCreated({age: 26});
createdEvent.watch(function(err, result) {
if (err) {
console.log(err)
return;
}
console.log("Found ", result);
})
Or you could filter all past events in similar fashion.
More information here
Best Answer
Logs are part of the transaction receipts. They are generated by the clients when executing transactions and stored alongside the blockchain to allow retrieving them.
Logs are not part of the blockchain itself per se, since they are not required for consensus (they are just historical data), however they are verified by the blockchain as the transaction receipt hashes are stored inside the blocks.