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
core/state: changes to journalling, part 1 #28880
base: master
Are you sure you want to change the base?
Conversation
ed6a316
to
2ccd040
Compare
(content moved to PR description) |
Where these changes are leading to is the following:
The
Instead of collecting this as 6 separate entries, it's sufficient if the very first Therefore, it is good if we can remove implementation-flags such as Example of how it can look: // journalAccountChange is the common shared implementation for all account-changes.
// These changes all fall back to this method:
// - balance change
// - nonce change
// - creation change (in this case, the account is nil)
func (j *scopedJournal) journaAccountChange(address common.Address, account types.StateAccount) {
// Unless the account has already been journalled, journal it now
if _, ok := accountChanges[address]; !ok {
if account != nil {
accountChanges[address] = types.SlimAccountRLP(account)
} else {
accountChanges[address] = nil
}
j.dirties[address]++
}
}
func (j *scopedJournal) JournalNonceChange(addr common.Address, account types.StateAccount) {
j.journaAccountChange(addr, account)
}
func (j *scopedJournal) JournalBalanceChange(addr common.Address, account types.StateAccount) {
j.journaAccountChange(address, account)
}
func (j *scopedJournal) JournalCreate(addr common.Address) {
j.journaAccountChange(addr, nil)
} |
d3f1ba7
to
f669216
Compare
The effect of the changes -- not on this branch, but no the even more experimental With
With set-based journal:
|
f669216
to
f1febe0
Compare
2290286
to
5eeeabd
Compare
5eeeabd
to
4c4faad
Compare
Now rebased to follow on top of #29627 |
c802f78
to
442fcf4
Compare
The self-destruct journalling is a bit strange: we allow the 'selfdestruct' operation to be journalled several times. This makes it so that we also are forced to store whether the account was already destructed. What we can do instead, is to only journal the first destruction, and after that only journal balance-changes, but not journal the selfdestruct itself. This simplifies the journalling, so that internals about state management does not leak into the journal-API.
We do not strictly need to journal preimages: preimages are stored and served for the benefit of remote RPC users, e.g. for debugging solidity storage. There is no 'consensus requirement' for these keys to be reverted in case of reverted scopes.
func (j *journal) Reset() { | ||
j.entries = j.entries[:0] | ||
j.validRevisions = j.validRevisions[:0] | ||
j.dirties = make(map[common.Address]int) |
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.
Might consider clear(j.dirties)
?
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.
Supposedly it empties a map's contents without deallocating it's capacity.
prevvalue: prevvalue, | ||
}) | ||
s.db.journal.JournalSetState(s.address, key, prevvalue) | ||
s.setState(key, &value) |
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.
The other methods called the logger first and then did the actual set. This PR moves this setState above it - but not in the other log events. I'm assuming it's a mistake?
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.
The logger
invocation is moved down, yes, because it's not "core". I wanted it to not be mixed in with the actual consensus code.
Since the values are already loaded into variables, it should be fine to do so.
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.
But every single other call has the logger happening first and then the state change.
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.
Yes, because consider this one:
if s.db.logger != nil && s.db.logger.OnBalanceChange != nil {
s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason)
}
In the call to the logger
, it actually uses the s.Balance()
. So it needs to be done before setting the new value. Alternatively, stash the value in a variable, so the logger
-call later on can use that.
So we're left with two crappy choices: introduce a (possibly unused) tempvar, or or do the logging-call in the middle of the core consensus mechanics.
This is a follow-up to #29520, and a preparatory PR to a more thorough change in the journalling system.
API methods instead of
append
operationsThis PR hides the journal-implementation details away, so that the statedb invokes methods like
JournalCreate
, instead of explicitly appending journal-events in a list. This means that it's up to the journal whether to implement it as a sequence of events or aggregate/merge events.Snapshot-management inside the journal
This PR also makes it so that management of valid snapshots is moved inside the journal, exposed via the methods
Snapshot() int
andRevertToSnapshot(revid int, s *StateDB)
.SetCode
JournalSetCode journals the setting of code: it is implicit that the previous values were "no code" and emptyCodeHash. Therefore, we can simplify the setCode journal.
Selfdestruct
The self-destruct journalling is a bit strange: we allow the selfdestruct operation to be journalled several times. This makes it so that we also are forced to store whether the account was already destructed.
What we can do instead, is to only journal the first destruction, and after that only journal balance-changes, but not journal the selfdestruct itself.
This simplifies the journalling, so that internals about state management does not leak into the journal-API.
Preimages
Preimages were, for some reason, integrated into the journal management, despite not being a consensus-critical data structure. This PR undoes that.