diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 72f9898e5a85..69a245322329 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2363,14 +2363,14 @@ func TestDeleteCreateRevert(t *testing.T) { } } -// TestDeleteRecreate tests a state-transition that contains both deletion +// TestDeleteRecreateSlots tests a state-transition that contains both deletion // and recreation of contract state. // Contract A exists, has slots 1 and 2 set // Tx 1: Selfdestruct A // Tx 2: Re-create A, set slots 3 and 4 // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, // and then the new slots exist -func TestDeleteRecreate(t *testing.T) { +func TestDeleteRecreateSlots(t *testing.T) { var ( // Generate a canonical chain to act as the main dataset engine = ethash.NewFaker() @@ -2490,3 +2490,76 @@ func TestDeleteRecreate(t *testing.T) { t.Fatalf("got %x exp %x", got, exp) } } + +// TestDeleteRecreateAccount tests a state-transition that contains deletion of a +// contract with storage, and a recreate of the same contract via a +// regular value-transfer +// Expected outcome is that _all_ slots are cleared from A +func TestDeleteRecreateAccount(t *testing.T) { + var ( + // Generate a canonical chain to act as the main dataset + engine = ethash.NewFaker() + db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + + aa = common.HexToAddress("0x7217d81b76bdd8707601e959454e3d776aee5f43") + aaStorage = make(map[common.Hash]common.Hash) // Initial storage in AA + aaCode = []byte{byte(vm.PC), 0xFF} // Code for AA (simple selfdestruct) + ) + // Populate two slots + aaStorage[common.HexToHash("01")] = common.HexToHash("01") + aaStorage[common.HexToHash("02")] = common.HexToHash("02") + + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + address: {Balance: funds}, + // The address 0xAAAAA selfdestructs if called + aa: { + // Code needs to just selfdestruct + Code: aaCode, + Nonce: 1, + Balance: big.NewInt(0), + Storage: aaStorage, + }, + }, + } + genesis := gspec.MustCommit(db) + + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + // One transaction to AA, to kill it + tx, _ := types.SignTx(types.NewTransaction(0, aa, + big.NewInt(0), 50000, big.NewInt(1), nil), types.HomesteadSigner{}, key) + b.AddTx(tx) + // One transaction to AA, to recreate it (but without storage + tx, _ = types.SignTx(types.NewTransaction(1, aa, + big.NewInt(1), 100000, big.NewInt(1), nil), types.HomesteadSigner{}, key) + b.AddTx(tx) + }) + // Import the canonical chain + diskdb := rawdb.NewMemoryDatabase() + gspec.MustCommit(diskdb) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ + Debug: true, + Tracer: vm.NewJSONLogger(nil, os.Stdout), + }, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + statedb, _ := chain.State() + + // If all is correct, then both slots are zero + if got, exp := statedb.GetState(aa, common.HexToHash("01")), (common.Hash{}); got != exp { + t.Errorf("got %x exp %x", got, exp) + } + if got, exp := statedb.GetState(aa, common.HexToHash("02")), (common.Hash{}); got != exp { + t.Errorf("got %x exp %x", got, exp) + } +}