|
|
|
@ -2287,3 +2287,78 @@ func TestSideImportPrunedBlocks(t *testing.T) { |
|
|
|
|
t.Errorf("Got error, %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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) { |
|
|
|
|
var ( |
|
|
|
|
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") |
|
|
|
|
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") |
|
|
|
|
// 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) |
|
|
|
|
gspec = &Genesis{ |
|
|
|
|
Config: params.TestChainConfig, |
|
|
|
|
Alloc: GenesisAlloc{ |
|
|
|
|
address: {Balance: funds}, |
|
|
|
|
// The address 0xAAAAA selfdestructs if called
|
|
|
|
|
aa: { |
|
|
|
|
// Code needs to just selfdestruct
|
|
|
|
|
Code: []byte{byte(vm.PC), 0xFF}, |
|
|
|
|
Nonce: 1, |
|
|
|
|
Balance: big.NewInt(0), |
|
|
|
|
}, |
|
|
|
|
// The address 0xBBBB send 1 wei to 0xAAAA, then reverts
|
|
|
|
|
bb: { |
|
|
|
|
Code: []byte{ |
|
|
|
|
byte(vm.PC), // [0]
|
|
|
|
|
byte(vm.DUP1), // [0,0]
|
|
|
|
|
byte(vm.DUP1), // [0,0,0]
|
|
|
|
|
byte(vm.DUP1), // [0,0,0,0]
|
|
|
|
|
byte(vm.PUSH1), 0x01, // [0,0,0,0,1] (value)
|
|
|
|
|
byte(vm.PUSH2), 0xaa, 0xaa, // [0,0,0,0,1, 0xaaaa]
|
|
|
|
|
byte(vm.GAS), |
|
|
|
|
byte(vm.CALL), |
|
|
|
|
byte(vm.REVERT), |
|
|
|
|
}, |
|
|
|
|
Balance: big.NewInt(1), |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
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 AAAA
|
|
|
|
|
tx, _ := types.SignTx(types.NewTransaction(0, aa, |
|
|
|
|
big.NewInt(0), 50000, big.NewInt(1), nil), types.HomesteadSigner{}, key) |
|
|
|
|
b.AddTx(tx) |
|
|
|
|
// One transaction to BBBB
|
|
|
|
|
tx, _ = types.SignTx(types.NewTransaction(1, bb, |
|
|
|
|
big.NewInt(0), 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{}, 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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|