From f572e8d716a6637466c4a40b55dbbaee3ac14f61 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Mon, 18 May 2020 01:27:58 -0500 Subject: [PATCH] finish testing known edge cases --- statediff/builder.go | 3 +- statediff/builder_test.go | 229 ++++++++++++++++++++++-- statediff/test_data/builder_test.go | 12 +- statediff/testhelpers/helpers.go | 28 ++- statediff/testhelpers/mocks/api_test.go | 4 +- 5 files changed, 249 insertions(+), 27 deletions(-) diff --git a/statediff/builder.go b/statediff/builder.go index afc46d406..2924716de 100644 --- a/statediff/builder.go +++ b/statediff/builder.go @@ -23,10 +23,9 @@ import ( "bytes" "fmt" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" diff --git a/statediff/builder_test.go b/statediff/builder_test.go index 5b73a5522..f5439eae8 100644 --- a/statediff/builder_test.go +++ b/statediff/builder_test.go @@ -464,7 +464,7 @@ var ( ) func TestBuilder(t *testing.T) { - blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis, testhelpers.TestChainGen) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) defer chain.Stop() block0 = testhelpers.Genesis @@ -689,7 +689,7 @@ func TestBuilder(t *testing.T) { } func TestBuilderWithIntermediateNodes(t *testing.T) { - blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis, testhelpers.TestChainGen) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) defer chain.Stop() block0 = testhelpers.Genesis @@ -960,7 +960,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { } func TestBuilderWithWatchedAddressList(t *testing.T) { - blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis, testhelpers.TestChainGen) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) defer chain.Stop() block0 = testhelpers.Genesis @@ -1129,7 +1129,7 @@ func TestBuilderWithWatchedAddressList(t *testing.T) { } func TestBuilderWithWatchedAddressAndStorageKeyList(t *testing.T) { - blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(3, testhelpers.Genesis, testhelpers.TestChainGen) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) defer chain.Stop() block0 = testhelpers.Genesis @@ -1286,7 +1286,7 @@ func TestBuilderWithWatchedAddressAndStorageKeyList(t *testing.T) { } func TestBuilderWithRemovedAccountAndStorage(t *testing.T) { - blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis, testhelpers.TestChainGen) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) defer chain.Stop() block3 = blocks[2] @@ -1492,8 +1492,8 @@ func TestBuilderWithRemovedAccountAndStorage(t *testing.T) { } } -func TestBuilderWithRemovedAccountAndStorageWithoutIntermediateStateNodes(t *testing.T) { - blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis) +func TestBuilderWithRemovedAccountAndStorageWithoutIntermediateNodes(t *testing.T) { + blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis, testhelpers.TestChainGen) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) defer chain.Stop() block3 = blocks[2] @@ -1502,7 +1502,7 @@ func TestBuilderWithRemovedAccountAndStorageWithoutIntermediateStateNodes(t *tes block6 = blocks[5] params := statediff.Params{ IntermediateStateNodes: false, - IntermediateStorageNodes: true, + IntermediateStorageNodes: false, } builder = statediff.NewBuilder(chain.StateCache()) @@ -1537,11 +1537,6 @@ func TestBuilderWithRemovedAccountAndStorageWithoutIntermediateStateNodes(t *tes LeafKey: contractLeafKey, NodeValue: contractAccountAtBlock4LeafNode, StorageDiffs: []statediff.StorageNode{ - { - Path: []byte{}, - NodeType: statediff.Branch, - NodeValue: block4StorageBranchRootNode, - }, { Path: []byte{'\x04'}, NodeType: statediff.Leaf, @@ -1681,6 +1676,214 @@ func TestBuilderWithRemovedAccountAndStorageWithoutIntermediateStateNodes(t *tes } } +var ( + slot00StorageValue = common.Hex2Bytes("9471562b71999873db5b286df957af199ec94617f7") // prefixed TestBankAddress + + slot00StorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"), + slot00StorageValue, + }) + + contractAccountAtBlock01, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(0), + CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), + Root: crypto.Keccak256Hash(block01StorageBranchRootNode), + }) + contractAccountAtBlock01LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3cb2583748c26e89ef19c2a8529b05a270f735553b4d44b6f2a1894987a71c8b"), + contractAccountAtBlock01, + }) + + bankAccountAtBlock01, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(testhelpers.TestBankFunds.Int64() + miningReward), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock01LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock01, + }) + bankAccountAtBlock02, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 2, + Balance: big.NewInt(testhelpers.TestBankFunds.Int64() + miningReward*2), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock02LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("2000bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock02, + }) + + block01BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + crypto.Keccak256Hash(bankAccountAtBlock01LeafNode), + crypto.Keccak256Hash(contractAccountAtBlock01LeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + }) + + block01StorageBranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + []byte{}, + []byte{}, + crypto.Keccak256(slot00StorageLeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(slot1StorageLeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + }) +) + +func TestBuilderWithMovedAccount(t *testing.T) { + blocks, chain := testhelpers.MakeChain(2, testhelpers.Genesis, testhelpers.TestSelfDestructChainGen) + contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) + defer chain.Stop() + block0 = testhelpers.Genesis + block1 = blocks[0] + block2 = blocks[1] + params := statediff.Params{ + IntermediateStateNodes: true, + IntermediateStorageNodes: true, + } + builder = statediff.NewBuilder(chain.StateCache()) + + var tests = []struct { + name string + startingArguments statediff.Args + expected *statediff.StateDiff + }{ + { + "testBlock1", + statediff.Args{ + OldStateRoot: block0.Root(), + NewStateRoot: block1.Root(), + BlockNumber: block1.Number(), + BlockHash: block1.Hash(), + }, + &statediff.StateDiff{ + BlockNumber: block1.Number(), + BlockHash: block1.Hash(), + Nodes: []statediff.StateNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block01BranchRootNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x00'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.BankLeafKey, + NodeValue: bankAccountAtBlock01LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x01'}, + NodeType: statediff.Leaf, + LeafKey: contractLeafKey, + NodeValue: contractAccountAtBlock01LeafNode, + StorageDiffs: []statediff.StorageNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block01StorageBranchRootNode, + }, + { + Path: []byte{'\x02'}, + NodeType: statediff.Leaf, + LeafKey: slot0StorageKey.Bytes(), + NodeValue: slot00StorageLeafNode, + }, + { + Path: []byte{'\x0b'}, + NodeType: statediff.Leaf, + LeafKey: slot1StorageKey.Bytes(), + NodeValue: slot1StorageLeafNode, + }, + }, + }, + }, + }, + }, + { + "testBlock2", + statediff.Args{ + OldStateRoot: block1.Root(), + NewStateRoot: block2.Root(), + BlockNumber: block2.Number(), + BlockHash: block2.Hash(), + }, + &statediff.StateDiff{ + BlockNumber: block2.Number(), + BlockHash: block2.Hash(), + Nodes: []statediff.StateNode{ + { + Path: []byte{}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.BankLeafKey, + NodeValue: bankAccountAtBlock02LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x01'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x00'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + }, + }, + }, + } + + for _, test := range tests { + diff, err := builder.BuildStateDiff(test.startingArguments, params) + if err != nil { + t.Error(err) + } + receivedStateDiffRlp, err := rlp.EncodeToBytes(diff) + if err != nil { + t.Error(err) + } + expectedStateDiffRlp, err := rlp.EncodeToBytes(test.expected) + if err != nil { + t.Error(err) + } + sort.Slice(receivedStateDiffRlp, func(i, j int) bool { return receivedStateDiffRlp[i] < receivedStateDiffRlp[j] }) + sort.Slice(expectedStateDiffRlp, func(i, j int) bool { return expectedStateDiffRlp[i] < expectedStateDiffRlp[j] }) + if !bytes.Equal(receivedStateDiffRlp, expectedStateDiffRlp) { + t.Logf("Test failed: %s", test.name) + t.Errorf("actual state diff: %+v\r\n\r\n\r\nexpected state diff: %+v", diff, test.expected) + } + } +} + /* pragma solidity ^0.5.10; diff --git a/statediff/test_data/builder_test.go b/statediff/test_data/builder_test.go index c568b672b..4fbf9a248 100644 --- a/statediff/test_data/builder_test.go +++ b/statediff/test_data/builder_test.go @@ -52,7 +52,7 @@ var ( // block 1 data block1CoinbaseAccount, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: big.NewInt(5000000000000000000), CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -124,7 +124,7 @@ var ( // block 2 data block2CoinbaseAccount, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: big.NewInt(5000000000000000000), CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -136,7 +136,7 @@ var ( block2CoinbaseLeafNodeHash = crypto.Keccak256(block2CoinbaseLeafNode) block2MovedPremineBalance, _ = new(big.Int).SetString("4000000000000000000000", 10) block2MovedPremineAccount, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: block2MovedPremineBalance, CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -230,7 +230,7 @@ var ( // path 060e0f blcok3CoinbaseBalance, _ = new(big.Int).SetString("5156250000000000000", 10) block3CoinbaseAccount, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: blcok3CoinbaseBalance, CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -243,7 +243,7 @@ var ( // path 0c0e050703 block3MovedPremineBalance1, _ = new(big.Int).SetString("3750000000000000000", 10) block3MovedPremineAccount1, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: block3MovedPremineBalance1, CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -256,7 +256,7 @@ var ( // path 0c0e050708 block3MovedPremineBalance2, _ = new(big.Int).SetString("1999944000000000000000", 10) block3MovedPremineAccount2, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: block3MovedPremineBalance2, CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, diff --git a/statediff/testhelpers/helpers.go b/statediff/testhelpers/helpers.go index 247128937..ab141c900 100644 --- a/statediff/testhelpers/helpers.go +++ b/statediff/testhelpers/helpers.go @@ -30,14 +30,34 @@ import ( // MakeChain creates a chain of n blocks starting at and including parent. // the returned hash chain is ordered head->parent. -func MakeChain(n int, parent *types.Block) ([]*types.Block, *core.BlockChain) { +func MakeChain(n int, parent *types.Block, chainGen func(int, *core.BlockGen)) ([]*types.Block, *core.BlockChain) { config := params.TestChainConfig - blocks, _ := core.GenerateChain(config, parent, ethash.NewFaker(), Testdb, n, testChainGen) + blocks, _ := core.GenerateChain(config, parent, ethash.NewFaker(), Testdb, n, chainGen) chain, _ := core.NewBlockChain(Testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) return blocks, chain } -func testChainGen(i int, block *core.BlockGen) { +func TestSelfDestructChainGen(i int, block *core.BlockGen) { + signer := types.HomesteadSigner{} + switch i { + case 0: + // Block 1 is mined by Account1Addr + // Account1Addr creates a new contract + block.SetCoinbase(TestBankAddress) + tx, _ := types.SignTx(types.NewContractCreation(0, big.NewInt(0), 1000000, big.NewInt(0), ContractCode), signer, TestBankKey) + ContractAddr = crypto.CreateAddress(TestBankAddress, 0) + block.AddTx(tx) + case 1: + // Block 2 is mined by Account1Addr + // Account1Addr self-destructs the contract + block.SetCoinbase(TestBankAddress) + data := common.Hex2Bytes("43D726D6") + tx, _ := types.SignTx(types.NewTransaction(1, ContractAddr, big.NewInt(0), 100000, nil, data), signer, TestBankKey) + block.AddTx(tx) + } +} + +func TestChainGen(i int, block *core.BlockGen) { signer := types.HomesteadSigner{} switch i { case 0: @@ -53,7 +73,7 @@ func testChainGen(i int, block *core.BlockGen) { tx2, _ := types.SignTx(types.NewTransaction(nonce, Account2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, Account1Key) nonce++ tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), ContractCode), signer, Account1Key) - ContractAddr = crypto.CreateAddress(Account1Addr, nonce) //0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592 + ContractAddr = crypto.CreateAddress(Account1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) block.AddTx(tx3) diff --git a/statediff/testhelpers/mocks/api_test.go b/statediff/testhelpers/mocks/api_test.go index e4779cd68..32d6e0b21 100644 --- a/statediff/testhelpers/mocks/api_test.go +++ b/statediff/testhelpers/mocks/api_test.go @@ -81,7 +81,7 @@ func TestAPI(t *testing.T) { } func testSubscriptionAPI(t *testing.T) { - blocks, chain := testhelpers.MakeChain(1, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(1, testhelpers.Genesis, testhelpers.TestChainGen) defer chain.Stop() block0 = testhelpers.Genesis block1 = blocks[0] @@ -165,7 +165,7 @@ func testSubscriptionAPI(t *testing.T) { } func testHTTPAPI(t *testing.T) { - blocks, chain := testhelpers.MakeChain(1, testhelpers.Genesis) + blocks, chain := testhelpers.MakeChain(1, testhelpers.Genesis, testhelpers.TestChainGen) defer chain.Stop() block0 = testhelpers.Genesis block1 = blocks[0]