diff --git a/statediff/builder_test.go b/statediff/builder_test.go index e7e927b4d..c1fee8919 100644 --- a/statediff/builder_test.go +++ b/statediff/builder_test.go @@ -33,14 +33,14 @@ import ( // TODO: add test that filters on address var ( - contractLeafKey, emptyContractLeafKey []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, emptyContractLeafKey, contract2LeafKey []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) balanceChange10000 = int64(10000) balanceChange1000 = int64(1000) @@ -1101,6 +1101,135 @@ func TestBuilderWithWatchedAddressAndStorageKeyList(t *testing.T) { } } +func TestBuilderWithMoreAndRemovedStorage(t *testing.T) { + blocks, chain := testhelpers.MakeChain(5, testhelpers.Genesis) + contractLeafKey = testhelpers.AddressToLeafKey(testhelpers.ContractAddr) + emptyContractLeafKey = testhelpers.AddressToLeafKey(testhelpers.EmptyContractAddr) + defer chain.Stop() + block4 := blocks[3] + block5 := blocks[4] + 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-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{}, + }, + }, + { + "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{}, + }, + }, + } + + 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{ + OldStateRoot: block5.Root(), + NewStateRoot: block6.Root(), + BlockNumber: block6.Number(), + BlockHash: block6.Hash(), + }, + &statediff.StateDiff{ + BlockNumber: block6.Number(), + BlockHash: block6.Hash(), + Nodes: []statediff.StateNode{}, + }, + }, + } + + 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) + } + } +} + // Write a test that tests when accounts are deleted, or moved to a new path /* diff --git a/statediff/testhelpers/helpers.go b/statediff/testhelpers/helpers.go index 5a6ac8fff..a939327dd 100644 --- a/statediff/testhelpers/helpers.go +++ b/statediff/testhelpers/helpers.go @@ -48,6 +48,8 @@ func testChainGen(i int, block *core.BlockGen) { nonce := block.TxNonce(TestBankAddress) tx1, _ := types.SignTx(types.NewTransaction(nonce, Account1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, TestBankKey) nonce++ + // this creates an empty contract at 2f30668e69d30b6fc1609db5447c101e40dda113ac28be157d20bb61da8e5861 + // it is created since we are not yet at EIP158 or Byzantium activation tx2, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), EmptyContractCode), signer, TestBankKey) EmptyContractAddr = crypto.CreateAddress(TestBankAddress, nonce) block.AddTx(tx1) @@ -76,23 +78,38 @@ func testChainGen(i int, block *core.BlockGen) { 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 account1 - block.SetCoinbase(Account1Addr) + // Block is mined by new Account3Addr + block.SetCoinbase(Account3Addr) data1 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000005") data2 := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002") - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), ContractAddr, big.NewInt(0), 100000, nil, data1), signer, TestBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), ContractAddr, big.NewInt(0), 100000, nil, data2), signer, TestBankKey) + 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 more txs from the bankAccount to the contract, that transfer no value and set slot positions to 0 - // Block is mined by new Account3Addr - block.SetCoinbase(Account3Addr) + // 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") - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), ContractAddr, big.NewInt(0), 100000, nil, data1), signer, TestBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(TestBankAddress), ContractAddr, big.NewInt(0), 100000, nil, data2), signer, TestBankKey) + 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) block.AddTx(tx1) block.AddTx(tx2) + case 5: + // Block 6 has a tx which creates a contract with leafkey 2f30668e69d30b6fc1609db5447c101e40dda113ac28be157d20bb61da8e5861 + // which means the empty contract at 2f30668e69d30b6fc1609db5447c101e40dda113ac28be157d20bb61da8e5861 must be moved to a new path + // this should count as "touching" that account and cause it to be removed according to EIP-158 + // Block is mined by Account2Addr + block.SetCoinbase(Account2Addr) + nonce := block.TxNonce(Account3Addr) + tx, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), ContractCode), signer, Account3Key) + ContractAddr2 = crypto.CreateAddress(Account3Addr, nonce) //0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592 + block.AddTx(tx) } } diff --git a/statediff/testhelpers/test_data.go b/statediff/testhelpers/test_data.go index b92791bee..6e1ef8b89 100644 --- a/statediff/testhelpers/test_data.go +++ b/statediff/testhelpers/test_data.go @@ -57,18 +57,18 @@ var ( TestBankFunds = big.NewInt(100000000) Genesis = core.GenesisBlockForTesting(Testdb, TestBankAddress, TestBankFunds) - 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) - Account3LeafKey = AddressToLeafKey(Account3Addr) - ContractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50602060405190810160405280600160ff16815250600090600161003592919061003b565b506100a5565b826064810192821561006f579160200282015b8281111561006e578251829060ff1690559160200191906001019061004e565b5b50905061007c9190610080565b5090565b6100a291905b8082111561009e576000816000905550600101610086565b5090565b90565b610124806100b46000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146054578063c16431b9146093575b600080fd5b607d60048036036020811015606857600080fd5b810190808035906020019092919050505060c8565b6040518082815260200191505060405180910390f35b60c66004803603604081101560a757600080fd5b81019080803590602001909291908035906020019092919050505060e0565b005b6000808260648110151560d757fe5b01549050919050565b8060008360648110151560ef57fe5b0181905550505056fea165627a7a7230582064e918c3140a117bf3aa65865a9b9e83fae21ad1720506e7933b2a9f54bb40260029") - EmptyContractCode []byte - ContractAddr, EmptyContractAddr common.Address + 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) + Account3LeafKey = AddressToLeafKey(Account3Addr) + ContractCode = common.Hex2Bytes("608060405234801561001057600080fd5b50602060405190810160405280600160ff16815250600090600161003592919061003b565b506100a5565b826064810192821561006f579160200282015b8281111561006e578251829060ff1690559160200191906001019061004e565b5b50905061007c9190610080565b5090565b6100a291905b8082111561009e576000816000905550600101610086565b5090565b90565b610124806100b46000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146054578063c16431b9146093575b600080fd5b607d60048036036020811015606857600080fd5b810190808035906020019092919050505060c8565b6040518082815260200191505060405180910390f35b60c66004803603604081101560a757600080fd5b81019080803590602001909291908035906020019092919050505060e0565b005b6000808260648110151560d757fe5b01549050919050565b8060008360648110151560ef57fe5b0181905550505056fea165627a7a7230582064e918c3140a117bf3aa65865a9b9e83fae21ad1720506e7933b2a9f54bb40260029") + EmptyContractCode []byte + ContractAddr, EmptyContractAddr, ContractAddr2 common.Address EmptyRootNode, _ = rlp.EncodeToBytes([]byte{}) EmptyContractRoot = crypto.Keccak256Hash(EmptyRootNode)