// VulcanizeDB // Copyright © 2019 Vulcanize // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package mocks import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/statediff/indexer/models" "github.com/ethereum/go-ethereum/statediff/test_helpers" sdtypes "github.com/ethereum/go-ethereum/statediff/types" "github.com/ethereum/go-ethereum/trie" ) // Test variables var ( // block data // TODO: Update this to `MainnetChainConfig` when `LondonBlock` is added TestConfig = params.RopstenChainConfig BlockNumber = TestConfig.LondonBlock MockHeader = types.Header{ Time: 0, Number: new(big.Int).Set(BlockNumber), Root: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"), Difficulty: big.NewInt(5000000), Extra: []byte{}, BaseFee: big.NewInt(params.InitialBaseFee), Coinbase: common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476777"), } MockTransactions, MockReceipts, SenderAddr = createTransactionsAndReceipts(TestConfig, BlockNumber) MockBlock = types.NewBlock(&MockHeader, MockTransactions, nil, MockReceipts, new(trie.Trie)) MockHeaderRlp, _ = rlp.EncodeToBytes(MockBlock.Header()) MockNonCanonicalHeader = MockHeader MockNonCanonicalBlockTransactions = types.Transactions{MockTransactions[1], MockTransactions[4]} MockNonCanonicalBlockReceipts = createNonCanonicalBlockReceipts(TestConfig, BlockNumber, MockNonCanonicalBlockTransactions) MockNonCanonicalBlock = types.NewBlock(&MockNonCanonicalHeader, MockNonCanonicalBlockTransactions, nil, MockNonCanonicalBlockReceipts, new(trie.Trie)) MockNonCanonicalHeaderRlp, _ = rlp.EncodeToBytes(MockNonCanonicalBlock.Header()) Block2Number = big.NewInt(BlockNumber.Int64() + 1) MockNonCanonicalHeader2 = types.Header{ Time: 0, Number: new(big.Int).Set(Block2Number), Root: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"), Difficulty: big.NewInt(6000000), Extra: []byte{}, BaseFee: big.NewInt(params.InitialBaseFee), Coinbase: common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476777"), } MockNonCanonicalBlock2Transactions = types.Transactions{MockTransactions[2], MockTransactions[4]} MockNonCanonicalBlock2Receipts = createNonCanonicalBlockReceipts(TestConfig, Block2Number, MockNonCanonicalBlock2Transactions) MockNonCanonicalBlock2 = types.NewBlock(&MockNonCanonicalHeader2, MockNonCanonicalBlock2Transactions, nil, MockNonCanonicalBlock2Receipts, new(trie.Trie)) MockNonCanonicalHeader2Rlp, _ = rlp.EncodeToBytes(MockNonCanonicalBlock2.Header()) Address = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592") AnotherAddress = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476593") ContractAddress = crypto.CreateAddress(SenderAddr, MockTransactions[2].Nonce()) ContractAddress2 = crypto.CreateAddress(SenderAddr, MockTransactions[3].Nonce()) MockContractByteCode = []byte{0, 1, 2, 3, 4, 5} mockTopic11 = common.HexToHash("0x04") mockTopic12 = common.HexToHash("0x06") mockTopic21 = common.HexToHash("0x05") mockTopic22 = common.HexToHash("0x07") ExpectedPostStatus uint64 = 1 ExpectedPostState1 = common.Bytes2Hex(common.HexToHash("0x1").Bytes()) ExpectedPostState2 = common.Bytes2Hex(common.HexToHash("0x2").Bytes()) ExpectedPostState3 = common.Bytes2Hex(common.HexToHash("0x3").Bytes()) MockLog1 = &types.Log{ Address: Address, Topics: []common.Hash{mockTopic11, mockTopic12}, Data: []byte{}, } MockLog2 = &types.Log{ Address: AnotherAddress, Topics: []common.Hash{mockTopic21, mockTopic22}, Data: []byte{}, } MockLog3 = &types.Log{ Address: Address, Topics: []common.Hash{mockTopic11, mockTopic22}, Data: []byte{}, } MockLog4 = &types.Log{ Address: AnotherAddress, Topics: []common.Hash{mockTopic21, mockTopic12}, Data: []byte{}, } ShortLog1 = &types.Log{ Address: AnotherAddress, Topics: []common.Hash{}, Data: []byte{}, } ShortLog2 = &types.Log{ Address: Address, Topics: []common.Hash{}, Data: []byte{}, } // access list entries AccessListEntry1 = types.AccessTuple{ Address: Address, } AccessListEntry2 = types.AccessTuple{ Address: AnotherAddress, StorageKeys: []common.Hash{common.BytesToHash(StorageLeafKey), common.BytesToHash(MockStorageLeafKey)}, } AccessListEntry1Model = models.AccessListElementModel{ BlockNumber: BlockNumber.String(), Index: 0, Address: Address.Hex(), } AccessListEntry2Model = models.AccessListElementModel{ BlockNumber: BlockNumber.String(), Index: 1, Address: AnotherAddress.Hex(), StorageKeys: []string{common.BytesToHash(StorageLeafKey).Hex(), common.BytesToHash(MockStorageLeafKey).Hex()}, } // statediff data storageLocation = common.HexToHash("0") StorageLeafKey = crypto.Keccak256Hash(storageLocation[:]).Bytes() mockStorageLocation = common.HexToHash("1") MockStorageLeafKey = crypto.Keccak256Hash(mockStorageLocation[:]).Bytes() StorageValue = common.Hex2Bytes("01") StoragePartialPath = common.Hex2Bytes("20290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") StorageLeafNode, _ = rlp.EncodeToBytes(&[]interface{}{ StoragePartialPath, StorageValue, }) nonce1 = uint64(1) ContractRoot = "0x821e2556a290c86405f8160a2d662042a431ba456b9db265c79bb837c04be5f0" ContractCodeHash = common.HexToHash("0x753f98a8d4328b15636e46f66f2cb4bc860100aa17967cc145fcd17d1d4710ea") ContractLeafKey = test_helpers.AddressToLeafKey(ContractAddress) ContractAccount, _ = rlp.EncodeToBytes(&types.StateAccount{ Nonce: nonce1, Balance: big.NewInt(0), CodeHash: ContractCodeHash.Bytes(), Root: common.HexToHash(ContractRoot), }) ContractPartialPath = common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45") ContractLeafNode, _ = rlp.EncodeToBytes(&[]interface{}{ ContractPartialPath, ContractAccount, }) Contract2LeafKey = test_helpers.AddressToLeafKey(ContractAddress2) storage2Location = common.HexToHash("2") Storage2LeafKey = crypto.Keccak256Hash(storage2Location[:]).Bytes() storage3Location = common.HexToHash("3") Storage3LeafKey = crypto.Keccak256Hash(storage3Location[:]).Bytes() nonce0 = uint64(0) AccountRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" AccountCodeHash = common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") AccountLeafKey = test_helpers.Account2LeafKey RemovedLeafKey = test_helpers.Account1LeafKey Account, _ = rlp.EncodeToBytes(&types.StateAccount{ Nonce: nonce0, Balance: big.NewInt(1000), CodeHash: AccountCodeHash.Bytes(), Root: common.HexToHash(AccountRoot), }) AccountPartialPath = common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45") AccountLeafNode, _ = rlp.EncodeToBytes(&[]interface{}{ AccountPartialPath, Account, }) StateDiffs = []sdtypes.StateNode{ { Path: []byte{'\x06'}, NodeType: sdtypes.Leaf, LeafKey: ContractLeafKey, NodeValue: ContractLeafNode, StorageNodes: []sdtypes.StorageNode{ { Path: []byte{}, NodeType: sdtypes.Leaf, LeafKey: StorageLeafKey, NodeValue: StorageLeafNode, }, { Path: []byte{'\x03'}, NodeType: sdtypes.Removed, LeafKey: RemovedLeafKey, NodeValue: []byte{}, }, }, }, { Path: []byte{'\x0c'}, NodeType: sdtypes.Leaf, LeafKey: AccountLeafKey, NodeValue: AccountLeafNode, StorageNodes: []sdtypes.StorageNode{}, }, { Path: []byte{'\x02'}, NodeType: sdtypes.Removed, LeafKey: RemovedLeafKey, NodeValue: []byte{}, }, { Path: []byte{'\x07'}, NodeType: sdtypes.Removed, LeafKey: Contract2LeafKey, NodeValue: []byte{}, StorageNodes: []sdtypes.StorageNode{ { Path: []byte{'\x0e'}, NodeType: sdtypes.Removed, LeafKey: Storage2LeafKey, NodeValue: []byte{}, }, { Path: []byte{'\x0f'}, NodeType: sdtypes.Removed, LeafKey: Storage3LeafKey, NodeValue: []byte{}, }, }, }, } ) type LegacyData struct { Config *params.ChainConfig BlockNumber *big.Int MockHeader types.Header MockTransactions types.Transactions MockReceipts types.Receipts SenderAddr common.Address MockBlock *types.Block MockHeaderRlp []byte Address []byte AnotherAddress []byte ContractAddress common.Address MockContractByteCode []byte MockLog1 *types.Log MockLog2 *types.Log StorageLeafKey []byte MockStorageLeafKey []byte StorageLeafNode []byte ContractLeafKey []byte ContractAccount []byte ContractPartialPath []byte ContractLeafNode []byte AccountRoot string AccountLeafNode []byte StateDiffs []sdtypes.StateNode } func NewLegacyData() *LegacyData { config := params.MainnetChainConfig // Block number before london fork. blockNumber := config.EIP155Block mockHeader := types.Header{ Time: 0, Number: new(big.Int).Set(blockNumber), Root: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"), Difficulty: big.NewInt(5000000), Extra: []byte{}, Coinbase: common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476888"), } mockTransactions, mockReceipts, senderAddr := createLegacyTransactionsAndReceipts(config, blockNumber) mockBlock := types.NewBlock(&mockHeader, mockTransactions, nil, mockReceipts, new(trie.Trie)) mockHeaderRlp, _ := rlp.EncodeToBytes(mockBlock.Header()) contractAddress := crypto.CreateAddress(senderAddr, mockTransactions[2].Nonce()) return &LegacyData{ Config: config, BlockNumber: blockNumber, MockHeader: mockHeader, MockTransactions: mockTransactions, MockReceipts: mockReceipts, SenderAddr: senderAddr, MockBlock: mockBlock, MockHeaderRlp: mockHeaderRlp, ContractAddress: contractAddress, MockContractByteCode: MockContractByteCode, MockLog1: MockLog1, MockLog2: MockLog2, StorageLeafKey: StorageLeafKey, MockStorageLeafKey: MockStorageLeafKey, StorageLeafNode: StorageLeafNode, ContractLeafKey: ContractLeafKey, ContractAccount: ContractAccount, ContractPartialPath: ContractPartialPath, ContractLeafNode: ContractLeafNode, AccountRoot: AccountRoot, AccountLeafNode: AccountLeafKey, StateDiffs: StateDiffs, } } // createLegacyTransactionsAndReceipts is a helper function to generate signed mock legacy transactions and mock receipts with mock logs func createLegacyTransactionsAndReceipts(config *params.ChainConfig, blockNumber *big.Int) (types.Transactions, types.Receipts, common.Address) { // make transactions trx1 := types.NewTransaction(0, Address, big.NewInt(1000), 50, big.NewInt(100), []byte{}) trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{}) trx3 := types.NewContractCreation(2, big.NewInt(1500), 75, big.NewInt(150), MockContractByteCode) transactionSigner := types.MakeSigner(config, blockNumber) mockCurve := elliptic.P256() mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) if err != nil { log.Crit(err.Error()) } signedTrx1, err := types.SignTx(trx1, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx2, err := types.SignTx(trx2, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx3, err := types.SignTx(trx3, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } senderAddr, err := types.Sender(transactionSigner, signedTrx1) // same for both trx if err != nil { log.Crit(err.Error()) } // make receipts mockReceipt1 := types.NewReceipt(nil, false, 50) mockReceipt1.Logs = []*types.Log{MockLog1} mockReceipt1.TxHash = signedTrx1.Hash() mockReceipt2 := types.NewReceipt(common.HexToHash("0x1").Bytes(), false, 100) mockReceipt2.Logs = []*types.Log{MockLog2, ShortLog1} mockReceipt2.TxHash = signedTrx2.Hash() mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 75) mockReceipt3.Logs = []*types.Log{} mockReceipt3.TxHash = signedTrx3.Hash() return types.Transactions{signedTrx1, signedTrx2, signedTrx3}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3}, senderAddr } // createTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs func createTransactionsAndReceipts(config *params.ChainConfig, blockNumber *big.Int) (types.Transactions, types.Receipts, common.Address) { // make transactions trx1 := types.NewTransaction(0, Address, big.NewInt(1000), 50, big.NewInt(100), []byte{}) trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{}) trx3 := types.NewContractCreation(2, big.NewInt(1500), 75, big.NewInt(150), MockContractByteCode) trx4 := types.NewTx(&types.AccessListTx{ ChainID: config.ChainID, Nonce: 0, GasPrice: big.NewInt(100), Gas: 50, To: &AnotherAddress, Value: big.NewInt(999), Data: []byte{}, AccessList: types.AccessList{ AccessListEntry1, AccessListEntry2, }, }) trx5 := types.NewTx(&types.DynamicFeeTx{ ChainID: config.ChainID, Nonce: 0, GasTipCap: big.NewInt(100), GasFeeCap: big.NewInt(100), Gas: 50, To: &AnotherAddress, Value: big.NewInt(1000), Data: []byte{}, AccessList: types.AccessList{ AccessListEntry1, AccessListEntry2, }, }) transactionSigner := types.MakeSigner(config, blockNumber) mockCurve := elliptic.P256() mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) if err != nil { log.Crit(err.Error()) } signedTrx1, err := types.SignTx(trx1, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx2, err := types.SignTx(trx2, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx3, err := types.SignTx(trx3, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx4, err := types.SignTx(trx4, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx5, err := types.SignTx(trx5, transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } senderAddr, err := types.Sender(transactionSigner, signedTrx1) // same for both trx if err != nil { log.Crit(err.Error()) } // make receipts mockReceipt1 := types.NewReceipt(nil, false, 50) mockReceipt1.Logs = []*types.Log{MockLog1} mockReceipt1.TxHash = signedTrx1.Hash() mockReceipt2 := types.NewReceipt(common.HexToHash("0x1").Bytes(), false, 100) mockReceipt2.Logs = []*types.Log{MockLog2, ShortLog1} mockReceipt2.TxHash = signedTrx2.Hash() mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 75) mockReceipt3.Logs = []*types.Log{} mockReceipt3.TxHash = signedTrx3.Hash() mockReceipt4 := &types.Receipt{ Type: types.AccessListTxType, PostState: common.HexToHash("0x3").Bytes(), Status: types.ReceiptStatusSuccessful, CumulativeGasUsed: 175, Logs: []*types.Log{MockLog3, MockLog4, ShortLog2}, TxHash: signedTrx4.Hash(), } mockReceipt5 := &types.Receipt{ Type: types.DynamicFeeTxType, PostState: common.HexToHash("0x3").Bytes(), Status: types.ReceiptStatusSuccessful, CumulativeGasUsed: 175, Logs: []*types.Log{}, TxHash: signedTrx5.Hash(), } return types.Transactions{signedTrx1, signedTrx2, signedTrx3, signedTrx4, signedTrx5}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3, mockReceipt4, mockReceipt5}, senderAddr } func createNonCanonicalBlockReceipts(config *params.ChainConfig, blockNumber *big.Int, transactions types.Transactions) types.Receipts { transactionSigner := types.MakeSigner(config, blockNumber) mockCurve := elliptic.P256() mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) if err != nil { log.Crit(err.Error()) } signedTrx0, err := types.SignTx(transactions[0], transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } signedTrx1, err := types.SignTx(transactions[1], transactionSigner, mockPrvKey) if err != nil { log.Crit(err.Error()) } mockReceipt0 := types.NewReceipt(common.HexToHash("0x3").Bytes(), false, 300) mockReceipt0.Logs = []*types.Log{MockLog1, ShortLog1} mockReceipt0.TxHash = signedTrx0.Hash() mockReceipt1 := &types.Receipt{ Type: types.DynamicFeeTxType, PostState: common.HexToHash("0x4").Bytes(), Status: types.ReceiptStatusSuccessful, CumulativeGasUsed: 300, Logs: []*types.Log{}, TxHash: signedTrx1.Hash(), } return types.Receipts{mockReceipt0, mockReceipt1} }