From e3b6d3df1cc148c625b5f9343a92bf28d1f188e1 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Sun, 17 May 2020 23:04:31 -0500 Subject: [PATCH] tests for eip-158 account removal and storage value deletions; there is one edge case left to test where we remove 1 account when only two exist such that the remaining account is moved up and replaces the root branch node --- statediff/builder.go | 42 +- statediff/builder_test.go | 858 ++++++++++++++++++++++------- statediff/testhelpers/helpers.go | 53 +- statediff/testhelpers/test_data.go | 6 - 4 files changed, 703 insertions(+), 256 deletions(-) diff --git a/statediff/builder.go b/statediff/builder.go index 946ed13d7..afc46d406 100644 --- a/statediff/builder.go +++ b/statediff/builder.go @@ -77,9 +77,9 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P return StateDiff{}, fmt.Errorf("error collecting createdAndUpdatedNodes: %v", err) } - // collect a slice of all the intermediate nodes that existed at A but don't at B + // collect a slice of all the nodes that existed at a path in A that doesn't exist in B // a map of their leafkey to all the accounts that were touched and exist at A - deletedIntermediateNodes, diffAccountsAtA, err := sdb.deletedOrUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), diffPathsAtB) + deletedNodes, diffAccountsAtA, err := sdb.deletedOrUpdatedState(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}), diffPathsAtB) if err != nil { return StateDiff{}, fmt.Errorf("error collecting deletedOrUpdatedNodes: %v", err) } @@ -104,17 +104,12 @@ func (sdb *builder) buildStateDiffWithIntermediateStateNodes(args Args, params P if err != nil { return StateDiff{}, fmt.Errorf("error building diff for created accounts: %v", err) } - // build the diff nodes for deleted accounts - deletedAccounts, err := sdb.buildAccountDeletions(diffAccountsAtA) - if err != nil { - return StateDiff{}, fmt.Errorf("error building diff for deleted accounts: %v", err) - } // assemble all of the nodes into the statediff object, including the intermediate nodes return StateDiff{ BlockNumber: args.BlockNumber, BlockHash: args.BlockHash, - Nodes: append(append(append(append(updatedAccounts, createdAccounts...), deletedAccounts...), createdOrUpdatedIntermediateNodes...), deletedIntermediateNodes...), + Nodes: append(append(append(updatedAccounts, createdAccounts...), createdOrUpdatedIntermediateNodes...), deletedNodes...), }, nil } @@ -298,10 +293,10 @@ func (sdb *builder) createdAndUpdatedState(a, b trie.NodeIterator) ([]StateNode, return createdOrUpdatedIntermediateNodes, diffAcountsAtB, diffPathsAtB, nil } -// deletedOrUpdatedState returns a slice of all the intermediate nodes that exist at A but not at B -// a mapping of their leafkeys to all the accounts that exist in a different state at A than B +// deletedOrUpdatedState returns a slice of all the nodes that exist at A but not at B +// and a mapping of their leafkeys to all the accounts that exist in a different state at A than B func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB map[string]bool) ([]StateNode, AccountMap, error) { - deletedIntermediateNodes := make([]StateNode, 0) + deletedNodes := make([]StateNode, 0) diffAccountAtA := make(AccountMap) it, _ := trie.NewDifferenceIterator(b, a) for it.Next(true) { @@ -314,6 +309,16 @@ func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB m } nodePath := make([]byte, len(it.Path())) copy(nodePath, it.Path()) + // if this nodePath did not show up in diffPathsAtB + // that means the node at this path was deleted (or moved) in B + // emit an empty "removed" diff to signify as such + if _, ok := diffPathsAtB[common.Bytes2Hex(nodePath)]; !ok { + deletedNodes = append(deletedNodes, StateNode{ + NodeType: Removed, + Path: nodePath, + NodeValue: []byte{}, + }) + } node, err := sdb.stateCache.TrieDB().Node(it.Hash()) if err != nil { return nil, nil, err @@ -345,21 +350,12 @@ func (sdb *builder) deletedOrUpdatedState(a, b trie.NodeIterator, diffPathsAtB m Account: &account, } case Extension, Branch: - // if this nodePath did not show up in diffPathsAtB - // that means the node at this path was deleted in B - // emit an empty "removed" diff to signify as such - if _, ok := diffPathsAtB[common.Bytes2Hex(nodePath)]; !ok { - deletedIntermediateNodes = append(deletedIntermediateNodes, StateNode{ - NodeType: Removed, - Path: nodePath, - NodeValue: []byte{}, - }) - } + // fall through, we did everything we need to do with these node types default: return nil, nil, fmt.Errorf("unexpected node type %s", ty) } } - return deletedIntermediateNodes, diffAccountAtA, nil + return deletedNodes, diffAccountAtA, nil } // buildAccountUpdates uses the account diffs maps for A => B and B => A and the known intersection of their leafkeys @@ -425,7 +421,6 @@ func (sdb *builder) buildAccountDeletions(accounts AccountMap) ([]StateNode, err accountDiffs = append(accountDiffs, StateNode{ NodeType: Removed, Path: val.Path, - LeafKey: val.LeafKey, NodeValue: []byte{}, }) } @@ -622,7 +617,6 @@ func (sdb *builder) deletedOrUpdatedStorage(a, b trie.NodeIterator, diffPathsAtB NodeType: Removed, Path: nodePath, NodeValue: []byte{}, - LeafKey: leafKey, }) } case Extension, Branch: diff --git a/statediff/builder_test.go b/statediff/builder_test.go index 7d6d43725..5b73a5522 100644 --- a/statediff/builder_test.go +++ b/statediff/builder_test.go @@ -33,65 +33,100 @@ import ( // TODO: add test that filters on address var ( - contractLeafKey []byte - emptyDiffs = make([]statediff.StateNode, 0) - emptyStorage = make([]statediff.StorageNode, 0) - block0, block1, block2, block3 *types.Block - builder statediff.Builder - miningReward = int64(2000000000000000000) - minerAddress = common.HexToAddress("0x0") - minerLeafKey = testhelpers.AddressToLeafKey(minerAddress) + contractLeafKey []byte + emptyDiffs = make([]statediff.StateNode, 0) + emptyStorage = make([]statediff.StorageNode, 0) + block0, block1, block2, block3, block4, block5, block6 *types.Block + builder statediff.Builder + miningReward = int64(2000000000000000000) + minerAddress = common.HexToAddress("0x0") + minerLeafKey = testhelpers.AddressToLeafKey(minerAddress) - balanceChange10000 = int64(10000) - balanceChange1000 = int64(1000) - block1BankBalance = int64(99990000) - block1Account1Balance = int64(10000) - block2Account2Balance = int64(1000) - contractContractRoot = "0x34fbee27a0db0e761bd121ba12d25fcc7bb12ff3fda9a0330e9dcdc91f676aa2" - newContractRoot = "0x89fb2012ce3e90bc3ba52a6831ff4722b93f6ea45d0d1311ce4432bd4abd2268" - ownerAddrStorageLocation = common.HexToHash("0") - ownerAddrStorageKey = crypto.Keccak256Hash(ownerAddrStorageLocation[:]) - originalStorageDataLocation = common.HexToHash("1") - originalDataStorageKey = crypto.Keccak256Hash(originalStorageDataLocation[:]) - newDataStorageLocation = common.HexToHash("3") - newStorageKey = crypto.Keccak256Hash(newDataStorageLocation[:]) - ownerAddrStorageValue = common.Hex2Bytes("94703c4b2bd70c169f5717101caee543299fc946c7") // prefixed AccountAddr1 - originalDataStorageValue = common.Hex2Bytes("01") - originalDataStorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("310e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), - originalDataStorageValue, - }) - ownerAddrStorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ + balanceChange10000 = int64(10000) + balanceChange1000 = int64(1000) + block1BankBalance = int64(99990000) + block1Account1Balance = int64(10000) + block2Account2Balance = int64(1000) + + slot0 = common.HexToHash("0") + slot1 = common.HexToHash("1") + slot2 = common.HexToHash("2") + slot3 = common.HexToHash("3") + + slot0StorageKey = crypto.Keccak256Hash(slot0[:]) + slot1StorageKey = crypto.Keccak256Hash(slot1[:]) + slot2StorageKey = crypto.Keccak256Hash(slot2[:]) + slot3StorageKey = crypto.Keccak256Hash(slot3[:]) + + slot0StorageValue = common.Hex2Bytes("94703c4b2bd70c169f5717101caee543299fc946c7") // prefixed AccountAddr1 + slot1StorageValue = common.Hex2Bytes("01") + slot2StorageValue = common.Hex2Bytes("09") + slot3StorageValue = common.Hex2Bytes("03") + + slot0StorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ common.Hex2Bytes("390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"), - ownerAddrStorageValue, + slot0StorageValue, }) - newDataStorageValue = common.Hex2Bytes("03") - newDataStorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ + slot1StorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("310e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"), + slot1StorageValue, + }) + slot2StorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("305787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"), + slot2StorageValue, + }) + slot3StorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{ common.Hex2Bytes("32575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b"), - newDataStorageValue, + slot3StorageValue, }) - bankAccountAtBlock0, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, - Balance: big.NewInt(testhelpers.TestBankFunds.Int64()), - CodeHash: testhelpers.NullCodeHash.Bytes(), - Root: testhelpers.EmptyContractRoot, + slot0StorageLeafRootNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("20290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"), + slot0StorageValue, }) - bankAccountAtBlock0LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("2000bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), - bankAccountAtBlock0, + + contractAccountAtBlock2, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(0), + CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), + Root: crypto.Keccak256Hash(block2StorageBranchRootNode), }) - account1AtBlock1, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, - Balance: big.NewInt(balanceChange10000), - CodeHash: testhelpers.NullCodeHash.Bytes(), - Root: testhelpers.EmptyContractRoot, + contractAccountAtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"), + contractAccountAtBlock2, }) - account1AtBlock1LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("3926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2"), - account1AtBlock1, + contractAccountAtBlock3, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(0), + CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), + Root: crypto.Keccak256Hash(block3StorageBranchRootNode), }) + contractAccountAtBlock3LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"), + contractAccountAtBlock3, + }) + contractAccountAtBlock4, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(0), + CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), + Root: crypto.Keccak256Hash(block4StorageBranchRootNode), + }) + contractAccountAtBlock4LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"), + contractAccountAtBlock4, + }) + contractAccountAtBlock5, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(0), + CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), + Root: crypto.Keccak256Hash(slot0StorageLeafRootNode), + }) + contractAccountAtBlock5LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"), + contractAccountAtBlock5, + }) + minerAccountAtBlock1, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: big.NewInt(miningReward), CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -100,58 +135,8 @@ var ( common.Hex2Bytes("3380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"), minerAccountAtBlock1, }) - bankAccountAtBlock1, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce1, - Balance: big.NewInt(testhelpers.TestBankFunds.Int64() - balanceChange10000), - CodeHash: testhelpers.NullCodeHash.Bytes(), - Root: testhelpers.EmptyContractRoot, - }) - bankAccountAtBlock1LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), - bankAccountAtBlock1, - }) - account2AtBlock2, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, - Balance: big.NewInt(balanceChange1000), - CodeHash: testhelpers.NullCodeHash.Bytes(), - Root: testhelpers.EmptyContractRoot, - }) - account2AtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45"), - account2AtBlock2, - }) - contractAccountAtBlock2, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce1, - Balance: big.NewInt(0), - CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), - Root: common.HexToHash(contractContractRoot), - }) - contractAccountAtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"), - contractAccountAtBlock2, - }) - bankAccountAtBlock2, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce2, - Balance: big.NewInt(block1BankBalance - balanceChange1000), - CodeHash: testhelpers.NullCodeHash.Bytes(), - Root: testhelpers.EmptyContractRoot, - }) - bankAccountAtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), - bankAccountAtBlock2, - }) - account1AtBlock2, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce2, - Balance: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000), - CodeHash: testhelpers.NullCodeHash.Bytes(), - Root: testhelpers.EmptyContractRoot, - }) - account1AtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("3926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2"), - account1AtBlock2, - }) minerAccountAtBlock2, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: big.NewInt(miningReward + miningReward), CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -160,8 +145,60 @@ var ( common.Hex2Bytes("3380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"), minerAccountAtBlock2, }) + + account1AtBlock1, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 0, + Balance: big.NewInt(balanceChange10000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + account1AtBlock1LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2"), + account1AtBlock1, + }) + account1AtBlock2, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 2, + Balance: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + account1AtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2"), + account1AtBlock2, + }) + account1AtBlock5, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 2, + Balance: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000 + miningReward), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + account1AtBlock5LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2"), + account1AtBlock5, + }) + account1AtBlock6, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 3, + Balance: big.NewInt(block1Account1Balance - balanceChange1000 + balanceChange1000 + miningReward), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + account1AtBlock6LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2"), + account1AtBlock6, + }) + + account2AtBlock2, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 0, + Balance: big.NewInt(balanceChange1000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + account2AtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45"), + account2AtBlock2, + }) account2AtBlock3, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce0, + Nonce: 0, Balance: big.NewInt(block2Account2Balance + miningReward), CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -170,18 +207,59 @@ var ( common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45"), account2AtBlock3, }) - contractAccountAtBlock3, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce1, - Balance: big.NewInt(0), - CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(), - Root: common.HexToHash(newContractRoot), + account2AtBlock4, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 0, + Balance: big.NewInt(block2Account2Balance + miningReward*2), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, }) - contractAccountAtBlock3LeafNode, _ = rlp.EncodeToBytes([]interface{}{ - common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"), - contractAccountAtBlock3, + account2AtBlock4LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45"), + account2AtBlock4, + }) + account2AtBlock6, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 0, + Balance: big.NewInt(block2Account2Balance + miningReward*3), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + account2AtBlock6LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45"), + account2AtBlock6, + }) + + bankAccountAtBlock0, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 0, + Balance: big.NewInt(testhelpers.TestBankFunds.Int64()), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock0LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("2000bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock0, + }) + bankAccountAtBlock1, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 1, + Balance: big.NewInt(testhelpers.TestBankFunds.Int64() - balanceChange10000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock1LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock1, + }) + bankAccountAtBlock2, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 2, + Balance: big.NewInt(block1BankBalance - balanceChange1000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock2LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock2, }) bankAccountAtBlock3, _ = rlp.EncodeToBytes(state.Account{ - Nonce: testhelpers.Nonce3, + Nonce: 3, Balance: big.NewInt(99989000), CodeHash: testhelpers.NullCodeHash.Bytes(), Root: testhelpers.EmptyContractRoot, @@ -190,8 +268,28 @@ var ( common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), bankAccountAtBlock3, }) + bankAccountAtBlock4, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 6, + Balance: big.NewInt(99989000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock4LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock4, + }) + bankAccountAtBlock5, _ = rlp.EncodeToBytes(state.Account{ + Nonce: 7, + Balance: big.NewInt(99989000), + CodeHash: testhelpers.NullCodeHash.Bytes(), + Root: testhelpers.EmptyContractRoot, + }) + bankAccountAtBlock5LeafNode, _ = rlp.EncodeToBytes([]interface{}{ + common.Hex2Bytes("30bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a"), + bankAccountAtBlock5, + }) - block1BranchNode, _ = rlp.EncodeToBytes([]interface{}{ + block1BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ crypto.Keccak256(bankAccountAtBlock1LeafNode), []byte{}, []byte{}, @@ -210,7 +308,7 @@ var ( []byte{}, []byte{}, }) - block2BranchNode, _ = rlp.EncodeToBytes([]interface{}{ + block2BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ crypto.Keccak256(bankAccountAtBlock2LeafNode), []byte{}, []byte{}, @@ -229,7 +327,7 @@ var ( []byte{}, []byte{}, }) - block3BranchNode, _ = rlp.EncodeToBytes([]interface{}{ + block3BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ crypto.Keccak256(bankAccountAtBlock3LeafNode), []byte{}, []byte{}, @@ -248,10 +346,68 @@ var ( []byte{}, []byte{}, }) - block2StorageBranchNode, _ = rlp.EncodeToBytes([]interface{}{ + block4BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + crypto.Keccak256(bankAccountAtBlock4LeafNode), []byte{}, []byte{}, - crypto.Keccak256(ownerAddrStorageLeafNode), + []byte{}, + []byte{}, + crypto.Keccak256(minerAccountAtBlock2LeafNode), + crypto.Keccak256(contractAccountAtBlock4LeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(account2AtBlock4LeafNode), + []byte{}, + crypto.Keccak256(account1AtBlock2LeafNode), + []byte{}, + []byte{}, + }) + block5BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + crypto.Keccak256(bankAccountAtBlock5LeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(minerAccountAtBlock2LeafNode), + crypto.Keccak256(contractAccountAtBlock5LeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(account2AtBlock4LeafNode), + []byte{}, + crypto.Keccak256(account1AtBlock5LeafNode), + []byte{}, + []byte{}, + }) + block6BranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + crypto.Keccak256(bankAccountAtBlock5LeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(minerAccountAtBlock2LeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(account2AtBlock6LeafNode), + []byte{}, + crypto.Keccak256(account1AtBlock6LeafNode), + []byte{}, + []byte{}, + }) + + block2StorageBranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + []byte{}, + []byte{}, + crypto.Keccak256(slot0StorageLeafNode), []byte{}, []byte{}, []byte{}, @@ -260,17 +416,38 @@ var ( []byte{}, []byte{}, []byte{}, - crypto.Keccak256(originalDataStorageLeafNode), + crypto.Keccak256(slot1StorageLeafNode), []byte{}, []byte{}, []byte{}, []byte{}, []byte{}, }) - block3StorageBranchNode, _ = rlp.EncodeToBytes([]interface{}{ + block3StorageBranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ []byte{}, []byte{}, - crypto.Keccak256(ownerAddrStorageLeafNode), + crypto.Keccak256(slot0StorageLeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + []byte{}, + crypto.Keccak256(slot1StorageLeafNode), + crypto.Keccak256(slot3StorageLeafNode), + []byte{}, + []byte{}, + []byte{}, + []byte{}, + }) + block4StorageBranchRootNode, _ = rlp.EncodeToBytes([]interface{}{ + []byte{}, + []byte{}, + crypto.Keccak256(slot0StorageLeafNode), + []byte{}, + crypto.Keccak256(slot2StorageLeafNode), []byte{}, []byte{}, []byte{}, @@ -279,8 +456,6 @@ var ( []byte{}, []byte{}, []byte{}, - crypto.Keccak256(originalDataStorageLeafNode), - crypto.Keccak256(newDataStorageLeafNode), []byte{}, []byte{}, []byte{}, @@ -423,14 +598,14 @@ func TestBuilder(t *testing.T) { { Path: []byte{'\x02'}, NodeType: statediff.Leaf, - LeafKey: ownerAddrStorageKey.Bytes(), - NodeValue: ownerAddrStorageLeafNode, + LeafKey: slot0StorageKey.Bytes(), + NodeValue: slot0StorageLeafNode, }, { Path: []byte{'\x0b'}, NodeType: statediff.Leaf, - LeafKey: originalDataStorageKey.Bytes(), - NodeValue: originalDataStorageLeafNode, + LeafKey: slot1StorageKey.Bytes(), + NodeValue: slot1StorageLeafNode, }, }, }, @@ -474,8 +649,8 @@ func TestBuilder(t *testing.T) { { Path: []byte{'\x0c'}, NodeType: statediff.Leaf, - LeafKey: newStorageKey.Bytes(), - NodeValue: newDataStorageLeafNode, + LeafKey: slot3StorageKey.Bytes(), + NodeValue: slot3StorageLeafNode, }, }, }, @@ -521,6 +696,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { block1 = blocks[0] block2 = blocks[1] block3 = blocks[2] + blocks = append([]*types.Block{block0}, blocks...) params := statediff.Params{ IntermediateStateNodes: true, IntermediateStorageNodes: true, @@ -585,7 +761,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { { Path: []byte{}, NodeType: statediff.Branch, - NodeValue: block1BranchNode, + NodeValue: block1BranchRootNode, StorageDiffs: emptyStorage, }, { @@ -630,7 +806,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { { Path: []byte{}, NodeType: statediff.Branch, - NodeValue: block2BranchNode, + NodeValue: block2BranchRootNode, StorageDiffs: emptyStorage, }, { @@ -663,19 +839,19 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { { Path: []byte{}, NodeType: statediff.Branch, - NodeValue: block2StorageBranchNode, + NodeValue: block2StorageBranchRootNode, }, { Path: []byte{'\x02'}, NodeType: statediff.Leaf, - LeafKey: ownerAddrStorageKey.Bytes(), - NodeValue: ownerAddrStorageLeafNode, + LeafKey: slot0StorageKey.Bytes(), + NodeValue: slot0StorageLeafNode, }, { Path: []byte{'\x0b'}, NodeType: statediff.Leaf, - LeafKey: originalDataStorageKey.Bytes(), - NodeValue: originalDataStorageLeafNode, + LeafKey: slot1StorageKey.Bytes(), + NodeValue: slot1StorageLeafNode, }, }, }, @@ -706,7 +882,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { { Path: []byte{}, NodeType: statediff.Branch, - NodeValue: block3BranchNode, + NodeValue: block3BranchRootNode, StorageDiffs: emptyStorage, }, { @@ -725,13 +901,13 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { { Path: []byte{}, NodeType: statediff.Branch, - NodeValue: block3StorageBranchNode, + NodeValue: block3StorageBranchRootNode, }, { Path: []byte{'\x0c'}, NodeType: statediff.Leaf, - LeafKey: newStorageKey.Bytes(), - NodeValue: newDataStorageLeafNode, + LeafKey: slot3StorageKey.Bytes(), + NodeValue: slot3StorageLeafNode, }, }, }, @@ -747,7 +923,7 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { }, } - for _, test := range tests { + for i, test := range tests { diff, err := builder.BuildStateDiff(test.startingArguments, params) if err != nil { t.Error(err) @@ -766,6 +942,20 @@ func TestBuilderWithIntermediateNodes(t *testing.T) { 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) } + // Let's also confirm that our root state nodes form the state root hash in the headers + if i > 0 { + block := blocks[i-1] + expectedStateRoot := block.Root() + for _, node := range test.expected.Nodes { + if bytes.Equal(node.Path, []byte{}) { + stateRoot := crypto.Keccak256Hash(node.NodeValue) + if !bytes.Equal(expectedStateRoot.Bytes(), stateRoot.Bytes()) { + t.Logf("Test failed: %s", test.name) + t.Errorf("actual stateroot: %x\r\nexpected stateroot: %x", stateRoot.Bytes(), expectedStateRoot.Bytes()) + } + } + } + } } } @@ -862,14 +1052,14 @@ func TestBuilderWithWatchedAddressList(t *testing.T) { { Path: []byte{'\x02'}, NodeType: statediff.Leaf, - LeafKey: ownerAddrStorageKey.Bytes(), - NodeValue: ownerAddrStorageLeafNode, + LeafKey: slot0StorageKey.Bytes(), + NodeValue: slot0StorageLeafNode, }, { Path: []byte{'\x0b'}, NodeType: statediff.Leaf, - LeafKey: originalDataStorageKey.Bytes(), - NodeValue: originalDataStorageLeafNode, + LeafKey: slot1StorageKey.Bytes(), + NodeValue: slot1StorageLeafNode, }, }, }, @@ -906,8 +1096,8 @@ func TestBuilderWithWatchedAddressList(t *testing.T) { { Path: []byte{'\x0c'}, NodeType: statediff.Leaf, - LeafKey: newStorageKey.Bytes(), - NodeValue: newDataStorageLeafNode, + LeafKey: slot3StorageKey.Bytes(), + NodeValue: slot3StorageLeafNode, }, }, }, @@ -948,7 +1138,7 @@ func TestBuilderWithWatchedAddressAndStorageKeyList(t *testing.T) { block3 = blocks[2] params := statediff.Params{ WatchedAddresses: []common.Address{testhelpers.Account1Addr, testhelpers.ContractAddr}, - WatchedStorageSlots: []common.Hash{originalDataStorageKey}, + WatchedStorageSlots: []common.Hash{slot1StorageKey}, } builder = statediff.NewBuilder(chain.StateCache()) @@ -1032,8 +1222,8 @@ func TestBuilderWithWatchedAddressAndStorageKeyList(t *testing.T) { { Path: []byte{'\x0b'}, NodeType: statediff.Leaf, - LeafKey: originalDataStorageKey.Bytes(), - NodeValue: originalDataStorageLeafNode, + LeafKey: slot1StorageKey.Bytes(), + NodeValue: slot1StorageLeafNode, }, }, }, @@ -1095,14 +1285,14 @@ func TestBuilderWithWatchedAddressAndStorageKeyList(t *testing.T) { } } -/* -func TestBuilderWithMoreAndRemovedStorage(t *testing.T) { - blocks, chain := testhelpers.MakeChain(5, testhelpers.Genesis) +func TestBuilderWithRemovedAccountAndStorage(t *testing.T) { + blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis) contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) - emptyContractLeafKey = testhelpers.AddressToLeafKey(testhelpers.EmptyContractAddr) defer chain.Stop() - block4 := blocks[3] - block5 := blocks[4] + block3 = blocks[2] + block4 = blocks[3] + block5 = blocks[4] + block6 = blocks[5] params := statediff.Params{ IntermediateStateNodes: true, IntermediateStorageNodes: true, @@ -1126,7 +1316,57 @@ func TestBuilderWithMoreAndRemovedStorage(t *testing.T) { &statediff.StateDiff{ BlockNumber: block4.Number(), BlockHash: block4.Hash(), - Nodes: []statediff.StateNode{}, + Nodes: []statediff.StateNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block4BranchRootNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x00'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.BankLeafKey, + NodeValue: bankAccountAtBlock4LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x06'}, + NodeType: statediff.Leaf, + LeafKey: contractLeafKey, + NodeValue: contractAccountAtBlock4LeafNode, + StorageDiffs: []statediff.StorageNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block4StorageBranchRootNode, + }, + { + Path: []byte{'\x04'}, + NodeType: statediff.Leaf, + LeafKey: slot2StorageKey.Bytes(), + NodeValue: slot2StorageLeafNode, + }, + { + Path: []byte{'\x0b'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x0c'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + }, + }, + { + Path: []byte{'\x0c'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account2LeafKey, + NodeValue: account2AtBlock4LeafNode, + StorageDiffs: emptyStorage, + }, + }, }, }, { @@ -1140,53 +1380,54 @@ func TestBuilderWithMoreAndRemovedStorage(t *testing.T) { &statediff.StateDiff{ BlockNumber: block5.Number(), BlockHash: block5.Hash(), - Nodes: []statediff.StateNode{}, + Nodes: []statediff.StateNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block5BranchRootNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x00'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.BankLeafKey, + NodeValue: bankAccountAtBlock5LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x06'}, + NodeType: statediff.Leaf, + LeafKey: contractLeafKey, + NodeValue: contractAccountAtBlock5LeafNode, + StorageDiffs: []statediff.StorageNode{ + { + Path: []byte{}, + NodeType: statediff.Leaf, + NodeValue: slot0StorageLeafRootNode, + LeafKey: slot0StorageKey.Bytes(), + }, + { + Path: []byte{'\x02'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x04'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + }, + }, + { + Path: []byte{'\x0e'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account1LeafKey, + NodeValue: account1AtBlock5LeafNode, + StorageDiffs: emptyStorage, + }, + }, }, }, - } - - 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) - } - } -} - -func TestBuilderWithEIP158RemovedAccount(t *testing.T) { - blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis) - contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) - emptyContractLeafKey = testhelpers.AddressToLeafKey(testhelpers.EmptyContractAddr) - contract2LeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr2) - defer chain.Stop() - block5 := blocks[4] - block6 := blocks[5] - params := statediff.Params{ - IntermediateStateNodes: true, - IntermediateStorageNodes: true, - } - builder = statediff.NewBuilder(chain.StateCache()) - - var tests = []struct { - name string - startingArguments statediff.Args - expected *statediff.StateDiff - }{ - // blocks 0-5 are the same as in TestBuilderWithIntermediateNodes and TestBuilderWithMoreAndRemovedStorage { "testBlock6", statediff.Args{ @@ -1198,7 +1439,222 @@ func TestBuilderWithEIP158RemovedAccount(t *testing.T) { &statediff.StateDiff{ BlockNumber: block6.Number(), BlockHash: block6.Hash(), - Nodes: []statediff.StateNode{}, + Nodes: []statediff.StateNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block6BranchRootNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x06'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x0c'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account2LeafKey, + NodeValue: account2AtBlock6LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x0e'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account1LeafKey, + NodeValue: account1AtBlock6LeafNode, + StorageDiffs: emptyStorage, + }, + }, + }, + }, + } + + 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) + } + } +} + +func TestBuilderWithRemovedAccountAndStorageWithoutIntermediateStateNodes(t *testing.T) { + blocks, chain := testhelpers.MakeChain(6, testhelpers.Genesis) + contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) + defer chain.Stop() + block3 = blocks[2] + block4 = blocks[3] + block5 = blocks[4] + block6 = blocks[5] + params := statediff.Params{ + IntermediateStateNodes: false, + IntermediateStorageNodes: true, + } + builder = statediff.NewBuilder(chain.StateCache()) + + var tests = []struct { + name string + startingArguments statediff.Args + expected *statediff.StateDiff + }{ + // blocks 0-3 are the same as in TestBuilderWithIntermediateNodes + { + "testBlock4", + statediff.Args{ + OldStateRoot: block3.Root(), + NewStateRoot: block4.Root(), + BlockNumber: block4.Number(), + BlockHash: block4.Hash(), + }, + &statediff.StateDiff{ + BlockNumber: block4.Number(), + BlockHash: block4.Hash(), + Nodes: []statediff.StateNode{ + { + Path: []byte{'\x00'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.BankLeafKey, + NodeValue: bankAccountAtBlock4LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x06'}, + NodeType: statediff.Leaf, + LeafKey: contractLeafKey, + NodeValue: contractAccountAtBlock4LeafNode, + StorageDiffs: []statediff.StorageNode{ + { + Path: []byte{}, + NodeType: statediff.Branch, + NodeValue: block4StorageBranchRootNode, + }, + { + Path: []byte{'\x04'}, + NodeType: statediff.Leaf, + LeafKey: slot2StorageKey.Bytes(), + NodeValue: slot2StorageLeafNode, + }, + { + Path: []byte{'\x0b'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x0c'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + }, + }, + { + Path: []byte{'\x0c'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account2LeafKey, + NodeValue: account2AtBlock4LeafNode, + StorageDiffs: emptyStorage, + }, + }, + }, + }, + { + "testBlock5", + statediff.Args{ + OldStateRoot: block4.Root(), + NewStateRoot: block5.Root(), + BlockNumber: block5.Number(), + BlockHash: block5.Hash(), + }, + &statediff.StateDiff{ + BlockNumber: block5.Number(), + BlockHash: block5.Hash(), + Nodes: []statediff.StateNode{ + { + Path: []byte{'\x00'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.BankLeafKey, + NodeValue: bankAccountAtBlock5LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x06'}, + NodeType: statediff.Leaf, + LeafKey: contractLeafKey, + NodeValue: contractAccountAtBlock5LeafNode, + StorageDiffs: []statediff.StorageNode{ + { + Path: []byte{}, + NodeType: statediff.Leaf, + NodeValue: slot0StorageLeafRootNode, + LeafKey: slot0StorageKey.Bytes(), + }, + { + Path: []byte{'\x02'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x04'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + }, + }, + { + Path: []byte{'\x0e'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account1LeafKey, + NodeValue: account1AtBlock5LeafNode, + StorageDiffs: emptyStorage, + }, + }, + }, + }, + { + "testBlock6", + statediff.Args{ + OldStateRoot: block5.Root(), + NewStateRoot: block6.Root(), + BlockNumber: block6.Number(), + BlockHash: block6.Hash(), + }, + &statediff.StateDiff{ + BlockNumber: block6.Number(), + BlockHash: block6.Hash(), + Nodes: []statediff.StateNode{ + { + Path: []byte{'\x06'}, + NodeType: statediff.Removed, + NodeValue: []byte{}, + }, + { + Path: []byte{'\x0c'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account2LeafKey, + NodeValue: account2AtBlock6LeafNode, + StorageDiffs: emptyStorage, + }, + { + Path: []byte{'\x0e'}, + NodeType: statediff.Leaf, + LeafKey: testhelpers.Account1LeafKey, + NodeValue: account1AtBlock6LeafNode, + StorageDiffs: emptyStorage, + }, + }, }, }, } @@ -1224,8 +1680,6 @@ func TestBuilderWithEIP158RemovedAccount(t *testing.T) { } } } -*/ -// Write a test that tests when accounts are deleted, or moved to a new path /* pragma solidity ^0.5.10; diff --git a/statediff/testhelpers/helpers.go b/statediff/testhelpers/helpers.go index 0deb6a1cd..247128937 100644 --- a/statediff/testhelpers/helpers.go +++ b/statediff/testhelpers/helpers.go @@ -32,8 +32,6 @@ import ( // the returned hash chain is ordered head->parent. func MakeChain(n int, parent *types.Block) ([]*types.Block, *core.BlockChain) { config := params.TestChainConfig - config.EIP158Block = big.NewInt(2) - config.ByzantiumBlock = big.NewInt(2) blocks, _ := core.GenerateChain(config, parent, ethash.NewFaker(), Testdb, n, testChainGen) chain, _ := core.NewBlockChain(Testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) return blocks, chain @@ -48,8 +46,8 @@ func testChainGen(i int, block *core.BlockGen) { block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. - // account1Addr passes it on to account #2. - // account1Addr creates a test contract. + // Account1Addr passes it on to account #2. + // Account1Addr creates a test contract. tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), Account1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, TestBankKey) nonce := block.TxNonce(Account1Addr) tx2, _ := types.SignTx(types.NewTransaction(nonce, Account2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, Account1Key) @@ -60,40 +58,47 @@ func testChainGen(i int, block *core.BlockGen) { block.AddTx(tx2) block.AddTx(tx3) case 2: - // Block 3 has a single tx from the bankAccount to the contract, that transfers no value, that is mined by account2 + // Block 3 has a single tx from the bankAccount to the contract, that transfers no value + // Block 3 is mined by Account2Addr block.SetCoinbase(Account2Addr) - //get function: 60cd2685 //put function: c16431b9 //close function: 43d726d6 data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003") tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), ContractAddr, big.NewInt(0), 100000, nil, data), signer, TestBankKey) block.AddTx(tx) case 3: - // Block 4 has two more txs from the bankAccount to the contract, that transfer no value - // Block is mined by new Account3Addr - block.SetCoinbase(Account3Addr) - data1 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000005") - data2 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002") + // Block 4 has three txs from bankAccount to the contract, that transfer no value + // Two set the two original slot positions to 0 and one sets another position to a new value + // Block 4 is mined by Account2Addr + block.SetCoinbase(Account2Addr) + data1 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + data2 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000") + data3 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000009") + nonce := block.TxNonce(TestBankAddress) tx1, _ := types.SignTx(types.NewTransaction(nonce, ContractAddr, big.NewInt(0), 100000, nil, data1), signer, TestBankKey) nonce++ tx2, _ := types.SignTx(types.NewTransaction(nonce, ContractAddr, big.NewInt(0), 100000, nil, data2), signer, TestBankKey) - block.AddTx(tx1) - block.AddTx(tx2) - case 4: - // Block 5 has two txs from Account3Addr to the contract, that transfer no value and set slot positions to 0 - // Account3Addr then creates a new contract - // Block is mined by Account2Addr - block.SetCoinbase(Account2Addr) - data1 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000") - data2 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000") - nonce := block.TxNonce(Account3Addr) - tx1, _ := types.SignTx(types.NewTransaction(nonce, ContractAddr, big.NewInt(0), 100000, nil, data1), signer, Account3Key) nonce++ - tx2, _ := types.SignTx(types.NewTransaction(nonce, ContractAddr, big.NewInt(0), 100000, nil, data2), signer, Account3Key) + tx3, _ := types.SignTx(types.NewTransaction(nonce, ContractAddr, big.NewInt(0), 100000, nil, data3), signer, TestBankKey) block.AddTx(tx1) block.AddTx(tx2) + block.AddTx(tx3) + case 4: + // Block 5 has one tx from bankAccount to the contract, that transfers no value + // It sets the remaining storage value to zero + // Block 5 is mined by Account1Addr + block.SetCoinbase(Account1Addr) + data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000") + nonce := block.TxNonce(TestBankAddress) + tx, _ := types.SignTx(types.NewTransaction(nonce, ContractAddr, big.NewInt(0), 100000, nil, data), signer, TestBankKey) + block.AddTx(tx) case 5: - // Block 6 has a tx which creates a contract with leafkey 2f30668e69d30b6fc1609db5447c101e40dda113ac28be157d20bb61da8e5861 + // Block 6 has a tx from Account1Key which self-destructs the contract, it transfers no value + // Block 6 is mined by Account2Addr + block.SetCoinbase(Account2Addr) + data := common.Hex2Bytes("43D726D6") + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(Account1Addr), ContractAddr, big.NewInt(0), 100000, nil, data), signer, Account1Key) + block.AddTx(tx) } } diff --git a/statediff/testhelpers/test_data.go b/statediff/testhelpers/test_data.go index 8b4e46af3..38273e15d 100644 --- a/statediff/testhelpers/test_data.go +++ b/statediff/testhelpers/test_data.go @@ -59,10 +59,8 @@ var ( Account1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") Account2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") - Account3Key, _ = crypto.HexToECDSA("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") Account1Addr = crypto.PubkeyToAddress(Account1Key.PublicKey) //0x703c4b2bD70c169f5717101CaeE543299Fc946C7 Account2Addr = crypto.PubkeyToAddress(Account2Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e - Account3Addr = crypto.PubkeyToAddress(Account3Key.PublicKey) //0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e Account1LeafKey = AddressToLeafKey(Account1Addr) Account2LeafKey = AddressToLeafKey(Account2Addr) ContractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060200160405280600160ff16815250600190600161007492919061007a565b506100e4565b82606481019282156100ae579160200282015b828111156100ad578251829060ff1690559160200191906001019061008d565b5b5090506100bb91906100bf565b5090565b6100e191905b808211156100dd5760008160009055506001016100c5565b5090565b90565b6101ca806100f36000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806343d726d61461003b578063c16431b914610045575b600080fd5b61004361007d565b005b61007b6004803603604081101561005b57600080fd5b81019080803590602001909291908035906020019092919050505061015c565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610122576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101746022913960400191505060405180910390fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b806001836064811061016a57fe5b0181905550505056fe4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f6e2ea265627a7a72305820e3747183708fb6bff3f6f7a80fb57dcc1c19f83f9cb25457a3ed5c0424bde66864736f6c634300050a0032") @@ -70,8 +68,4 @@ var ( EmptyRootNode, _ = rlp.EncodeToBytes([]byte{}) EmptyContractRoot = crypto.Keccak256Hash(EmptyRootNode) - Nonce0 = uint64(0) - Nonce1 = uint64(1) - Nonce2 = uint64(2) - Nonce3 = uint64(3) )