-
Notifications
You must be signed in to change notification settings - Fork 5
feat: Add Firewood implementation #240
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
base: main
Are you sure you want to change the base?
Conversation
| parentRoot common.Hash | ||
| root common.Hash | ||
| reader database.Reader | ||
| dirtyKeys map[string][]byte // Store dirty changes |
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.
You could use sync.Map as a direct replacement or add a sync.RWMutex to guard access to the map.
Also consider if sharing AccountTrie instances across goroutines is necessary, or if each goroutine should have its own copy.
| } | ||
|
|
||
| // This function only reads from existing tracked proposals, so we can use a read lock. | ||
| db.proposalLock.RLock() |
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.
We need a write lock to clean up old proposals and store new ones:
db.proposalLock.Lock()
defer db.proposalLock.Unlock()
db.possibleProposals = nil
Clean up should be mandatory, because (I suppose) this releases references to Rust memory held via FFI.
Maybe you can do a clean up function that can do this operation atomically, because I think there are lots of places where you would need to do this.
| // Edge case: first set of proposals before `Commit`, or empty genesis block | ||
| // Neither `Update` nor `Commit` is called for genesis, so we can accept a proposal with parentHash of empty. | ||
| for _, possible := range db.possibleProposals { | ||
| if possible.info.parent.hashes[common.Hash{}] == struct{}{} { |
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.
Since hashes is map[common.Hash]struct{}, accessing a non-existent key returns the zero value struct{}{}, making this comparison always true when the key doesn't exist. This is a logic bug - it should check if the key exists.
| if possible.info.parent.hashes[common.Hash{}] == struct{}{} { | |
| if _, ok := possible.info.parent.hashes[common.Hash{}]; ok { |
Why this should be merged
This is the first step in integrating Firewood into libevm for shared use in coreth and subnet-evm. This PR includes the
triedb.DBOverrideimplementation, as well as thestate.Trieimplementations necessary to inject intostate.Database. This is essentially a re-write of the current implementation in coreth, so feel free to suggest any structural changes. Let's get it right this time.Note this cannot be merged until the next Firewood release. The automatic proposal cleanup and some bug fixes are necessary.
The most notable difference from coreth is a performance difference (see ava-labs/coreth#1238)
How this works
All the logic is essentially the same as before, with the exception of proposal creation and cleanup. Proposals are now created at hash time, and then rather than being dropped, are passed to the triedb for potential commit.
How this was tested
Sorry, there's no unit tests. I'm thinking PR 2 will be creating the
state.Databaseinjections and fixing the fuzz test in coreth. However, you can test this by checking outalarso16/firewood-libevmin coreth, using somego mod editstatements, and building firewood locally. It passes all coreth tests.