refactor(levm,l1,l2): split block execution and update generation#2519
Conversation
Lines of code reportTotal lines added: Detailed view |
| if chain_config.fork(block.header.timestamp) != fork { | ||
| return Err(( | ||
| ChainError::Custom("Crossing fork boundary in bulk mode".into()), | ||
| Some(BatchBlockProcessingFailure { |
There was a problem hiding this comment.
I think is a bit confusing, since the problem is not that the block n is invalid, but that the caller made a mistake by calling this functions with blocks from different forks.
There was a problem hiding this comment.
Maybe a new error variant?
There was a problem hiding this comment.
We should handle this (if we cannot avoid it) in caller code (aka full sync) as crossing fork boundaries in a batch is something that will eventually happen when syncing networks. This probably exceeds the scope of this PR but we should create an issue for it
There was a problem hiding this comment.
agreed with @fmoletta, we should create a ticket and handle this from the caller. But I think it's better to also check this from inside and return an error.
There was a problem hiding this comment.
See conversation in slack. This shouldn't be a problem since we're only dealing with post merge networks and we should be able to do batch block processing across fork boundaries.
| Ok(v) => v, | ||
| Err(err) => return Err((ChainError::EvmError(err), None)), | ||
| }; | ||
| for account_update in account_updates { |
There was a problem hiding this comment.
not sure what this does, but it seems weird do do account updates processing in the blockchain crate. From a design perspective, it seems this should be done inside the vm crate and that blockchain crate should just get results and update the db?
There was a problem hiding this comment.
Actually now that a single get_state_transition call is made, this merge isn't needed. Fixed.
There was a problem hiding this comment.
Yep, we also don't need to use all_account_updates nor the for loop. We can just send account_updates directly to the apply_account_updates method.
| let account_updates = result.account_updates; | ||
| let _result = vm.execute_block(&block)?; | ||
| // let receipts = result.receipts; | ||
| let account_updates = vm.get_state_transitions(fork)?; |
There was a problem hiding this comment.
hmm, weird to pass the current fork to the get_state_transitions function. From the outside, it doesn't make much sense.
There was a problem hiding this comment.
It's needed because because SpuriousDragon changed the rules on remotion from the trie
There was a problem hiding this comment.
But we don't support SpuriousDragon, so maybe we can avoid this?
There was a problem hiding this comment.
Yes, I wanted to remove that in the past but the thing is that the State EF Tests test for Spurious Dragon and we use this same method. As per my understanding LEVM will ideally support all forks, but if we change opinion on that then it's ok to remove the fork.
There was a problem hiding this comment.
The vm should know which fork the block was executed from, so when calling get_state_transitions it should have that information internally. It should not be passed explicitly. Otherwise I could execute a Cacun block and then ask for the state transitions for SpuriousDragon
There was a problem hiding this comment.
Yes! The VM knows the fork but the thing is that get_state_transitions is not a method from the actual VM. It is just a function of the LEVM module in the intersection between L1 and the VM. Maybe it should be a VM method though.
There was a problem hiding this comment.
Adding to this. Our VM just exists in the context of a transaction, after executing one we discard the VM and the only thing that's left is the modified state, so we lose that VM instance that knew which fork it was executing. I agree that it's not nice to pass the fork, for now we can just disable SpuriousDragon checks
There was a problem hiding this comment.
The LEVM DB doesn't currently keep track of which blocks it executed.
Benchmark Block Execution Results Comparison Against Main
|
| let account_updates = match vm.get_state_transitions(fork) { | ||
| Ok(v) => v, | ||
| Err(err) => return Err((ChainError::EvmError(err), None)), | ||
| }; |
There was a problem hiding this comment.
| let account_updates = match vm.get_state_transitions(fork) { | |
| Ok(v) => v, | |
| Err(err) => return Err((ChainError::EvmError(err), None)), | |
| }; | |
| let account_updates = vm.get_state_transitions(fork).map_err(|err| (ChainError::EvmError(err), None))?; |
nit
| panic!("invalid database") | ||
| }; | ||
|
|
||
| let fork = db.chain_config.fork(block.header.timestamp); |
There was a problem hiding this comment.
This is not necessary when running with REVM
…mbdaclass#2519) **Motivation** Currently during batch processing, the state transitions are calculated for every block and then merged, when it would be more performant to calculate them once at the end. **Description** This PR removes the account updates from the execution result and makes every consumer manually request them. <!-- Link to issues: Resolves lambdaclass#111, Resolves lambdaclass#222 --> Closes lambdaclass#2504
Motivation
Currently during batch processing, the state transitions are calculated for every block and then merged, when it would be more performant to calculate them once at the end.
Description
This PR removes the account updates from the execution result and makes every consumer manually request them.
Closes #2504