zksync-era
zksync-era copied to clipboard
feat: Transfer event removal
What ❔
Divide web3 server API into 2:
- Old one
- Test-drive API, which won't return ETH Transfer events
API that will be run per instance is defined via config:
- API_WEB3_JSON_RPC_ETH_TRANSFER_EVENTS(disabled/enabled) modes
- EN_ETH_TRANSFER_EVENTS(disabled/enabled) modes
Added new columns to events
database to reassign indexes of logs correctly(added SQL migrations and Rust migrations, mostly inspired by https://github.com/matter-labs/zksync-era/pull/688):
-
event_index_in_block_without_eth_transfer
-
event_index_in_tx_without_eth_transfer
Why ❔
To be EVM compatible.
Checklist
- [x] PR title corresponds to the body of PR (we generate changelog entries from PRs).
- [x] Tests for the changes have been added / updated.
- [x] Documentation comments have been added / updated.
- [x] Code has been formatted via
zk fmt
andzk lint
. - [x] Spellcheck has been run via
cargo spellcheck --cfg=./spellcheck/era.cfg --code 1
.
Do we need to fully ignore Transfer events? e.g. they appear and impact log indexes, is it okay to be this way or it is better to somehow change this behaviour?
this is definitely not a chore
. Remember that chore
doesn't end up in changelog. This is a feat
.
A really late question, sorry for not raising it before. What if the event filtering is controlled via an additional field in Filter
(used in eth_newFilter
and eth_getLogs
) / PubSubFilter
(used in subscriptions) with a default value? In this case, a single API server could serve both new and legacy API (we may need to spin up 2 notifier tasks for logs instead of one; one with filtering and the other without it), and filtering would be controlled by the client. Would this contradict some other requirements / not work / require too much effort to integrate into Web3 clients? (I'd guess they should have interceptor functionality that would allow doing that, but I don't have much experience using Web3 clients.)
cc @RomanBrodetski @montekki @popzxc
What if the event filtering is controlled via an additional field in Filter (used in eth_newFilter and eth_getLogs) / PubSubFilter (used in subscriptions) with a default value?
@slowli I believe most people use SDKs (ethers and such) for that, and in most cases modifying the logic of interacting with filters is hidden. Probably it won't work.
@popzxc For ethers in particular, the interceptor abstraction I've talked about is encapsulated in the Provider
interface. Specifically, BaseProvider
(a base for other providers) defines _getFilter
, which AFAIU maps all event filters processed by the provider (this is in ethers v5 used in integration tests; in ethers v6, it's structured similarly). So it seems possible to do something like this:
interface FilterWithEthTransfers extends Filter {
filterEthTransfers?: boolean;
}
class CustomizableProvider extends zksync.Provider {
private filterEthTransfers: boolean;
override async _getFilter(filter: Filter | /* ... */): Promise<FilterWithEthTransfers | /* ... */> {
const resolvedFilter = <FilterWithEthTransfers>await super._getFilter(filter);
resolvedFilter.filterEthTransfers = this.filterEthTransfers; // passed to JSON-RPC call
return resolvedFilter;
}
}
IMO, controlling filtering on the client side makes the approach more maintainable and easier to reason about, both for us and clients. OTOH, I may be unaware of complexities associated with modifying and maintaining client code.
@slowli I think that if anything more complex than just "swap URL" would be required, people would just not bother. Though I may be wrong, cc @RomanBrodetski
No performance difference detected (anymore)
@Artemka374 is this PR still relevant or can it be closed?
I don't know to be honest. The discussion about it was brought up again not that long ago, but I don't remember any decision was made. Maybe @RomanBrodetski or @StanislavBreadless can say more?
I believe it will be needed in the long term anyway, so better to finish it up and get into production