ethereumjs / ethereumjs-blockstream

Reliable stream of Ethereum blocks
MIT License
80 stars 18 forks source link

Feature Request: Log filter aggregation #15

Open MicahZoltu opened 6 years ago

MicahZoltu commented 6 years ago

Currently, if you add several filters, each one will result in a separate request for logs via eth_getLogs. These filters could be aggregated so that we only make one request to eth_getLogs.

The implementation for this would look something like (pseudocode):

Object.keys(this.logFilters).reduce((accumulator, currentValue) => {
    accumulator.address.concat(currentValue.address)
    accumulator.topics.forEach((topic, index) => topic.concat(currentValue.topics[index]))
}, { address: [], topics: [[], [], [], []] })

and be put somewhere around https://github.com/ethereumjs/ethereumjs-blockstream/blob/master/source/block-and-log-streamer.ts#L76

Note: Users who expressly want separate calls can choose to not use block-and-log-streamer and instead use one of the lower level primitives. block-and-log streamer is meant to be mildly opinionated.

MicahZoltu commented 6 years ago

Probably going to close this as won't fix because log aggregation is non-trivial when you have multiple topics.

address: [0xbaad, 0xf00d],
topics: [ [0xcafe, 0xdead], [0xbeef, 0xbabe] ]

translates to

(address == 0xbaad || address == 0xf00d) && (topics[0] == 0xcafe || topics[0] == 0xdead) && (topics[1] == 0xbeef || topics[1] == 0xbabe)

The above filter would be created from the following two filters aggregated together naively:

address: 0xbaad
topics: [0xcafe, [0xbeef, 0xbabe]]

address: 0xf00d
topics: [0xdead]

Note that the second filter wouldn't match anything when aggregated together because its logs have neither 0xbeef or 0xbabe for the second topic.

We could resolve this by having the aggregation include null in any empty position, so the second filter would be interpreted as:

address: 0xf00d
topics: [0xdead, null, null, null]

But then it means that if you have a single filter like:

address: 0xf00d
topics: []

you will get all logs from any transaction that matches any of the addresses.

We certainly could support this, but it feels like we should leave aggregation up to the caller since they have more context as to what they are doing and what makes the most sense for them. Some people may want two very specific logs, one of which just has a single topic and the other has all 4 topics.