-
Notifications
You must be signed in to change notification settings - Fork 20.5k
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: fix bug in copy of copy State #16485
Conversation
@holiman @karalabe Thanks again for proposing a fix for the reported issue this quickly. I just applied the patch to check if this fixes the tests that started failing in my automated smart contract analysis tool after I had updated go-ethereum. It seems like this did the trick and the tests pass again. |
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state) | ||
state.stateObjectsDirty[addr] = 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.
Here you are iterating over all the state objects, even non dirty ones and set them to dirty in lower layers. Are you sure this is what you intended? Am I missing something?
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.
Yeah, that is most likely wrong
How the heck did this PR succeed building?
|
Apparently @holiman you based this PR on your own master branch (which was stale) and not upstream master. Or not sure what funky issue happened, but this branch is 28 commits behind master. Will force push. EDIT: Done. |
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.
Please modify the code so it only copies the actually dirty objects, but not the clean ones:
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 3b8faa287..f18e0a47d 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -477,13 +477,12 @@ func (self *StateDB) Copy() *StateDB {
// Above, we don't copy the actual journal. This means that if the copy is copied, the
// loop above will be a no-op, since the copy:s journal is empty.
// Thus, here we iterate over stateObjects, to enable copies of copies
- for addr := range self.stateObjects {
+ for addr := range self.stateObjectsDirty {
if _, exist := state.stateObjects[addr]; !exist {
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
state.stateObjectsDirty[addr] = struct{}{}
}
}
-
for hash, logs := range self.logs {
state.logs[hash] = make([]*types.Log, len(logs))
copy(state.logs[hash], logs)
Oh, and pls also fix |
Done, ptal |
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.
LGTM
@holiman @karalabe I just pulled these changes and encountered a crash that seems to be related. Unfortunately, I can't easily reproduce it. However, here is parts of the stack trace:
Any idea what might be going wrong here? This might be completely unrelated, but while looking at the code for
|
Interesting. so there is an |
Regarding the second question, I believe that is correct. It copies over all modified storage entries to the copy, but does not bother copying non-modified data. |
Oh, btw @wuestholz , did you use the original PR or the fixed/squashed one? What's the commit hash? |
@holiman I see. Thanks for looking into it! In case that helps, I'm using a local in-memory chain (with the chain config for mainnet) to run sequences of transactions to detect issues in smart contracts. I might be able to get the sequence of transactions in case that helps. Yes, I'm using the fixed one (5a79aca). |
If you are using pre-byzantium rules, it may be the that you run into the case documented here: https://github.com/ethereum/go-ethereum/blob/master/core/state/statedb.go#L532 . If that's the case, that would be good news. Otherwise, you may have found some other cornercase, which I would be very grateful if you were able to reproduce/diagnose. |
@holiman Hm. I'm using the same chain config as mainnet and it seems that the block numbers are around 4007428. I assume that would be pre-byzantium, right? |
Yes, byzantium is at |
@holiman Yes, that's what seems to be happening. The non-existing address is indeed 0000000000000000000000000000000000000003 for my run. Below you can see the sequence of transactions (as json) that seem to trigger the behavior in case you want to try to reproduce it:
|
Thanks for confirming! I'll follow up with a nil-check |
Great! Thank you very much for fixing this so quickly! |
Fixes #15225 (comment) . The copied state did not contain the full journal, and when that was copied, the dirty tracking was lost.