|
|
@@ -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)
|
|
|
+ }
|
|
|
+}
|