aboutsummaryrefslogtreecommitdiffstats
path: root/core/state/statedb_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/state/statedb_test.go')
-rw-r--r--core/state/statedb_test.go35
1 files changed, 35 insertions, 0 deletions
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index bf073bc94..bb3b87ead 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -449,3 +449,38 @@ func TestCopyOfCopy(t *testing.T) {
t.Fatalf("2nd copy fail, expected 42, got %v", got)
}
}
+
+// TestDeleteCreateRevert tests a weird state transition corner case that we hit
+// while changing the internals of statedb. The workflow is that a contract is
+// self destructed, then in a followup transaction (but same block) it's created
+// again and the transaction reverted.
+//
+// The original statedb implementation flushed dirty objects to the tries after
+// each transaction, so this works ok. The rework accumulated writes in memory
+// first, but the journal wiped the entire state object on create-revert.
+func TestDeleteCreateRevert(t *testing.T) {
+ // Create an initial state with a single contract
+ state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
+
+ addr := toAddr([]byte("so"))
+ state.SetBalance(addr, big.NewInt(1))
+
+ root, _ := state.Commit(false)
+ state.Reset(root)
+
+ // Simulate self-destructing in one transaction, then create-reverting in another
+ state.Suicide(addr)
+ state.Finalise(true)
+
+ id := state.Snapshot()
+ state.SetBalance(addr, big.NewInt(2))
+ state.RevertToSnapshot(id)
+
+ // Commit the entire state and make sure we don't crash and have the correct state
+ root, _ = state.Commit(true)
+ state.Reset(root)
+
+ if state.getStateObject(addr) != nil {
+ t.Fatalf("self-destructed contract came alive")
+ }
+}