-
Notifications
You must be signed in to change notification settings - Fork 55
refactor(levm): implement cache rollback #2417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Lines of code reportTotal lines added: Detailed view
|
Benchmark Results ComparisonPR ResultsBenchmark Results: Factorial
Benchmark Results: Factorial - Recursive
Benchmark Results: Fibonacci
Benchmark Results: ManyHashes
Benchmark Results: BubbleSort
Benchmark Results: ERC20 - Transfer
Benchmark Results: ERC20 - Mint
Benchmark Results: ERC20 - Approval
Main ResultsBenchmark Results: Factorial
Benchmark Results: Factorial - Recursive
Benchmark Results: Fibonacci
Benchmark Results: ManyHashes
Benchmark Results: BubbleSort
Benchmark Results: ERC20 - Transfer
Benchmark Results: ERC20 - Mint
Benchmark Results: ERC20 - Approval
|
EF Tests Comparison
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good, just two comments
crates/vm/levm/src/db/gen_db.rs
Outdated
|
||
/// Gets mutable account, first checking the cache and then the database | ||
/// (caching in the second case) | ||
/// This isn't a method of VM because it allows us to use it during VM initialization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this line comment adds much to this method documentation. Having this method on the GeneralizedDatabase
makes more sense than having it on the VM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed here
crates/vm/levm/src/db/gen_db.rs
Outdated
pub fn get_account_mut<'a>( | ||
&'a mut self, | ||
address: Address, | ||
call_frame: Option<&mut CallFrame>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it is not super clear here why you are passing an Option<CallFrame>
.
If you want to make the cache backup optional, then maybe we need something a bit more expressive.
The best I came up with right now is to have
type CacheBackup = HashMap<Address, Option<Account>>;
pub fn get_account_mut<'a>(
&'a mut self,
address: Address,
cache_backup: Option<&mut CacheBackup>);
// The call would be
self.db.get_account_mut(address, Some(call_frame.previous_cache_state))?;
self.db.get_account_mut(address, None)?;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to say, I changed it here
**Motivation** <!-- Why does this pull request exist? What are its goals? --> - merge main changes to my other PR because main had a huge refactor and my PR was also a huge refactor :) **Description** <!-- A clear and concise general description of the changes this PR introduces --> <!-- Link to issues: Resolves #111, Resolves #222 --> Closes #issue_number --------- Co-authored-by: Julian Ventura <[email protected]> Co-authored-by: Avila Gastón <[email protected]> Co-authored-by: fmoletta <[email protected]> Co-authored-by: Matías Onorato <[email protected]> Co-authored-by: Edgar <[email protected]> Co-authored-by: Tomás Arjovsky <[email protected]> Co-authored-by: Martin Paulucci <[email protected]> Co-authored-by: Lucas Fiegl <[email protected]> Co-authored-by: Estéfano Bargas <[email protected]> Co-authored-by: Javier Rodríguez Chatruc <[email protected]> Co-authored-by: VolodymyrBg <[email protected]> Co-authored-by: Tomás Paradelo <[email protected]> Co-authored-by: Mauro Toscano <[email protected]> Co-authored-by: Cypher Pepe <[email protected]>
…nto levm/cache_rollback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left you some nit comments. We should take a look at the clones, since the recent flamegraph that we made while syning in holesky showed us that we spend too much time cloning data from hashmaps and Account
.
Anyways, the code LGTM and it has shown some performance improvements while syncing, so good work!
We can merge and try to remove some data cloning in other PR
// ================== Account related functions ===================== | ||
/// Gets account, first checking the cache and then the database | ||
/// (caching in the second case) | ||
pub fn get_account(&mut self, address: Address) -> Result<Account, DatabaseError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we return a reference to the Account
here, instead of cloning it? The caller may clone if it needs to.
Cloning too many accounts may be expensive, even more if those Accounts are contracts (contain bytecode and storage).
} | ||
|
||
/// Gets account without pushing it to the cache | ||
pub fn get_account_no_push_cache(&self, address: Address) -> Result<Account, DatabaseError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
&mut self, | ||
accrued_substate: &mut Substate, | ||
address: Address, | ||
) -> Result<(AccountInfo, bool), DatabaseError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we may be ok by cloning the AccountInfo
, since it does not contain the bytecode nor storage
// ================== Account related functions ===================== | ||
|
||
pub fn get_account_mut(&mut self, address: Address) -> Result<&mut Account, VMError> { | ||
if !cache::is_account_cached(&self.db.cache, &address) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Instead of interacting with the db.cache
, why don't you make a function for the storage which retrieves what you want?
In this case, we could have a get_account_mut
on the GeneralizedDatabase
which returns a mutable reference to the Account
.
You can then clone that if you want to store it in the backup.
This PR has become too big so the best option is to merge it and address the comments later :) |
Motivation
Description
cache_backup
, that stores the pre-write state of the account that the callframe is trying to mutate. If the context reverts that state is restored in the cache. Otherwise, the parent call frame inherits the changes of the child of the accounts that only the child has modified, so that if the parent callframe reverts it can revert what the child did.GeneralizedDatabase
VM
. Basically it accesses the database backup up if there's a callframe available for doing so.Some other changes that it makes:
finalize_execution
. Specifically the reversion of value transfer and removal of check for coinbase transfer of gas fee.utils.rs
andgen_db.rs
so thatvm.rs
keeps main functionalities.Closes #issue_number