From a683e45855837c0d1b00e0d8362945edaeb9248b Mon Sep 17 00:00:00 2001 From: Rob Mulholand Date: Fri, 20 Jul 2018 11:37:46 -0500 Subject: [PATCH] Consolidate test doubles - Migrate various mocks of core namespaces to shared version in `fakes` pkg - Err on the side of making test doubles less sophisticated - Don't pull over mocks of namespaces that are only used in example code --- cmd/erc20.go | 20 ++-- cmd/lightSync.go | 24 ++-- cmd/sync.go | 23 ++-- examples/erc20_watcher/every_block/fetcher.go | 11 +- .../erc20_watcher/every_block/fetcher_test.go | 61 ++++------ .../every_block/integration_test.go | 13 +- .../erc20_watcher/every_block/transformer.go | 4 +- .../every_block/transformer_test.go | 22 ++-- examples/mocks/mocks.go | 93 ++------------- integration_test/block_rewards_test.go | 33 +++--- integration_test/contract_test.go | 39 +++--- integration_test/geth_blockchain_test.go | 21 ++-- libraries/shared/transformer_interface.go | 2 +- libraries/shared/watcher.go | 2 +- libraries/shared/watcher_test.go | 2 +- pkg/core/blockchain.go | 2 +- pkg/core/{client.go => eth_client.go} | 5 +- pkg/core/rpc_client.go | 9 ++ pkg/datastore/inmemory/block_repository.go | 51 -------- pkg/datastore/inmemory/contract_repository.go | 35 ------ pkg/datastore/inmemory/header_repository.go | 30 ----- pkg/datastore/inmemory/in_memory.go | 32 ----- pkg/fakes/mock_block_repository.go | 85 +++++++------ pkg/fakes/mock_blockchain.go | 112 ++++++++---------- .../{mock_client.go => mock_eth_client.go} | 70 ++++++++--- pkg/fakes/mock_header_repository.go | 40 +++++++ pkg/fakes/mock_rpc_client.go | 73 ++++++++++++ pkg/geth/blockchain.go | 4 +- pkg/geth/blockchain_test.go | 14 +-- pkg/geth/client/client.go | 33 ------ pkg/geth/client/eth_client.go | 42 +++++++ pkg/geth/client/rpc_client.go | 30 +++++ .../converters/common/block_converter_test.go | 86 +++----------- .../converters/rpc/transaction_converter.go | 15 +-- pkg/geth/node/node.go | 89 +++++++------- pkg/geth/node/node_test.go | 82 +++---------- pkg/history/block_validator.go | 4 +- pkg/history/block_validator_test.go | 28 ++--- pkg/history/header_validator.go | 4 +- pkg/history/header_validator_test.go | 33 ++---- pkg/history/populate_blocks.go | 4 +- pkg/history/populate_blocks_test.go | 97 ++++----------- pkg/history/populate_headers.go | 4 +- pkg/history/populate_headers_test.go | 33 ++---- pkg/history/validation_window.go | 2 +- pkg/history/validation_window_test.go | 15 +-- 46 files changed, 640 insertions(+), 893 deletions(-) rename pkg/core/{client.go => eth_client.go} (62%) create mode 100644 pkg/core/rpc_client.go delete mode 100644 pkg/datastore/inmemory/block_repository.go delete mode 100644 pkg/datastore/inmemory/contract_repository.go delete mode 100644 pkg/datastore/inmemory/header_repository.go delete mode 100644 pkg/datastore/inmemory/in_memory.go rename pkg/fakes/{mock_client.go => mock_eth_client.go} (52%) create mode 100644 pkg/fakes/mock_header_repository.go create mode 100644 pkg/fakes/mock_rpc_client.go delete mode 100644 pkg/geth/client/client.go create mode 100644 pkg/geth/client/eth_client.go create mode 100644 pkg/geth/client/rpc_client.go diff --git a/cmd/erc20.go b/cmd/erc20.go index 95f78ae8..9a9cacde 100644 --- a/cmd/erc20.go +++ b/cmd/erc20.go @@ -15,18 +15,20 @@ package cmd import ( + "log" + "time" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/spf13/cobra" + "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" "github.com/vulcanize/vulcanizedb/libraries/shared" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" - rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" + vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "log" - "time" ) // erc20Cmd represents the erc20 command @@ -54,15 +56,15 @@ Expects an ethereum node to be running and requires a .toml config file: func watchERC20s() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() - rpcClient, err := rpc.Dial(ipc) + rawRpcClient, err := rpc.Dial(ipc) if err != nil { log.Fatal(err) } - ethClient := ethclient.NewClient(rpcClient) - client := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ContextCaller: rpcClient, IPCPath: ipc} - node := node.MakeNode(clientWrapper) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + rpcClient := client.NewRpcClient(rawRpcClient, ipc) + ethClient := ethclient.NewClient(rawRpcClient) + client := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) + transactionConverter := vRpc.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(client, node, transactionConverter) db, err := postgres.NewDB(databaseConfig, blockChain.Node()) if err != nil { diff --git a/cmd/lightSync.go b/cmd/lightSync.go index 224e364f..242c1e53 100644 --- a/cmd/lightSync.go +++ b/cmd/lightSync.go @@ -15,21 +15,23 @@ package cmd import ( + "log" + "os" + "time" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/spf13/cobra" + "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" - rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" + vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" "github.com/vulcanize/vulcanizedb/pkg/history" "github.com/vulcanize/vulcanizedb/utils" - "log" - "os" - "time" ) // lightSyncCmd represents the lightSync command @@ -61,22 +63,22 @@ func init() { lightSyncCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block number to start syncing from") } -func backFillAllHeaders(blockchain core.Blockchain, headerRepository datastore.HeaderRepository, missingBlocksPopulated chan int, startingBlockNumber int64) { +func backFillAllHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, missingBlocksPopulated chan int, startingBlockNumber int64) { missingBlocksPopulated <- history.PopulateMissingHeaders(blockchain, headerRepository, startingBlockNumber) } func lightSync() { ticker := time.NewTicker(pollingInterval) defer ticker.Stop() - rpcClient, err := rpc.Dial(ipc) + rawRpcClient, err := rpc.Dial(ipc) if err != nil { log.Fatal(err) } - ethClient := ethclient.NewClient(rpcClient) - client := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ContextCaller: rpcClient, IPCPath: ipc} - node := node.MakeNode(clientWrapper) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + rpcClient := client.NewRpcClient(rawRpcClient, ipc) + ethClient := ethclient.NewClient(rawRpcClient) + client := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) + transactionConverter := vRpc.NewRpcTransactionConverter(client) blockChain := geth.NewBlockChain(client, node, transactionConverter) lastBlock := blockChain.LastBlock().Int64() diff --git a/cmd/sync.go b/cmd/sync.go index 1e958aa3..99d89973 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -15,21 +15,20 @@ package cmd import ( - "os" - - "time" - "log" + "os" + "time" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/spf13/cobra" + "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" - rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" + vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" "github.com/vulcanize/vulcanizedb/pkg/history" "github.com/vulcanize/vulcanizedb/utils" @@ -70,22 +69,22 @@ func init() { syncCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block number to start syncing from") } -func backFillAllBlocks(blockchain core.Blockchain, blockRepository datastore.BlockRepository, missingBlocksPopulated chan int, startingBlockNumber int64) { +func backFillAllBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, missingBlocksPopulated chan int, startingBlockNumber int64) { missingBlocksPopulated <- history.PopulateMissingBlocks(blockchain, blockRepository, startingBlockNumber) } func sync() { ticker := time.NewTicker(pollingInterval) defer ticker.Stop() - rpcClient, err := rpc.Dial(ipc) + rawRpcClient, err := rpc.Dial(ipc) if err != nil { log.Fatal(err) } - ethClient := ethclient.NewClient(rpcClient) - client := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ContextCaller: rpcClient, IPCPath: ipc} - node := node.MakeNode(clientWrapper) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + rpcClient := client.NewRpcClient(rawRpcClient, ipc) + ethClient := ethclient.NewClient(rawRpcClient) + client := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) + transactionConverter := vRpc.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(client, node, transactionConverter) lastBlock := blockChain.LastBlock().Int64() diff --git a/examples/erc20_watcher/every_block/fetcher.go b/examples/erc20_watcher/every_block/fetcher.go index c42f1050..e644b0c5 100644 --- a/examples/erc20_watcher/every_block/fetcher.go +++ b/examples/erc20_watcher/every_block/fetcher.go @@ -16,24 +16,25 @@ package every_block import ( "fmt" - "github.com/vulcanize/vulcanizedb/pkg/core" "log" "math/big" + + "github.com/vulcanize/vulcanizedb/pkg/core" ) type ERC20FetcherInterface interface { FetchSupplyOf(contractAbi string, contractAddress string, blockNumber int64) (big.Int, error) - GetBlockchain() core.Blockchain + GetBlockChain() core.BlockChain } -func NewFetcher(blockchain core.Blockchain) Fetcher { +func NewFetcher(blockchain core.BlockChain) Fetcher { return Fetcher{ Blockchain: blockchain, } } type Fetcher struct { - Blockchain core.Blockchain + Blockchain core.BlockChain ContractAbi string ContractAddress string } @@ -65,6 +66,6 @@ func (f Fetcher) FetchSupplyOf(contractAbi string, contractAddress string, block return *result, nil } -func (f Fetcher) GetBlockchain() core.Blockchain { +func (f Fetcher) GetBlockChain() core.BlockChain { return f.Blockchain } diff --git a/examples/erc20_watcher/every_block/fetcher_test.go b/examples/erc20_watcher/every_block/fetcher_test.go index f74e078c..9ca34486 100644 --- a/examples/erc20_watcher/every_block/fetcher_test.go +++ b/examples/erc20_watcher/every_block/fetcher_test.go @@ -15,68 +15,50 @@ package every_block_test import ( + "math/big" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/examples/mocks" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "math/big" ) var _ = Describe("ERC20 Fetcher", func() { blockNumber := int64(5502914) - infuraIPC := "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" - var errorFetcher every_block.Fetcher - var realFetcher every_block.Fetcher - var testFetcher every_block.Fetcher - var fakeBlockchain *mocks.Blockchain - var testAbi string - var testContractAddress string - - BeforeEach(func() { - rpcClient, err := rpc.Dial(infuraIPC) - Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: infuraIPC, - } - node := node.MakeNode(clientWrapper) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) - realBlockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) - realFetcher = every_block.NewFetcher(realBlockChain) - fakeBlockchain = &mocks.Blockchain{} - testFetcher = every_block.NewFetcher(fakeBlockchain) - testAbi = "testAbi" - testContractAddress = "testContractAddress" - - errorBlockchain := &mocks.FailureBlockchain{} - errorFetcher = every_block.NewFetcher(errorBlockchain) - }) Describe("FetchSupplyOf", func() { It("fetches data from the blockchain with the correct arguments", func() { + fakeBlockchain := fakes.NewMockBlockChain() + testFetcher := every_block.NewFetcher(fakeBlockchain) + testAbi := "testAbi" + testContractAddress := "testContractAddress" _, err := testFetcher.FetchSupplyOf(testAbi, testContractAddress, blockNumber) Expect(err).NotTo(HaveOccurred()) - Expect(fakeBlockchain.FetchedAbi).To(Equal(testAbi)) - Expect(fakeBlockchain.FetchedContractAddress).To(Equal(testContractAddress)) - Expect(fakeBlockchain.FetchedMethod).To(Equal("totalSupply")) - Expect(fakeBlockchain.FetchedMethodArg).To(BeNil()) expectedResult := big.Int{} expected := &expectedResult - Expect(fakeBlockchain.FetchedResult).To(Equal(&expected)) - Expect(fakeBlockchain.FetchedBlockNumber).To(Equal(blockNumber)) + fakeBlockchain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "totalSupply", nil, &expected, blockNumber) }) It("fetches a token's total supply at the given block height", func() { + infuraIPC := "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" + rawRpcClient, err := rpc.Dial(infuraIPC) + Expect(err).NotTo(HaveOccurred()) + rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) + transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) + realFetcher := every_block.NewFetcher(blockChain) result, err := realFetcher.FetchSupplyOf(constants.DaiAbiString, constants.DaiContractAddress, blockNumber) Expect(err).NotTo(HaveOccurred()) @@ -86,12 +68,15 @@ var _ = Describe("ERC20 Fetcher", func() { }) It("returns an error if the call to the blockchain fails", func() { + blockChain := fakes.NewMockBlockChain() + blockChain.SetFetchContractDataErr(fakes.FakeError) + errorFetcher := every_block.NewFetcher(blockChain) result, err := errorFetcher.FetchSupplyOf("", "", 0) Expect(result.String()).To(Equal("0")) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("totalSupply")) - Expect(err.Error()).To(ContainSubstring(mocks.TestError.Error())) + Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) }) }) }) diff --git a/examples/erc20_watcher/every_block/integration_test.go b/examples/erc20_watcher/every_block/integration_test.go index 0443d00c..52dfa435 100644 --- a/examples/erc20_watcher/every_block/integration_test.go +++ b/examples/erc20_watcher/every_block/integration_test.go @@ -20,34 +20,35 @@ import ( "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" - "github.com/vulcanize/vulcanizedb/examples/mocks" "github.com/vulcanize/vulcanizedb/examples/test_helpers" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "math/big" "strconv" ) -func setLastBlockOnChain(blockchain *mocks.Blockchain, blockNumber int64) { +func setLastBlockOnChain(blockChain *fakes.MockBlockChain, blockNumber int64) { blockNumberString := strconv.FormatInt(blockNumber, 10) lastBlockOnChain := big.Int{} lastBlockOnChain.SetString(blockNumberString, 10) - blockchain.SetLastBlock(&lastBlockOnChain) + blockChain.SetLastBlock(&lastBlockOnChain) } var _ = Describe("Everyblock transformers", func() { var db *postgres.DB - var blockchain mocks.Blockchain + var blockChain *fakes.MockBlockChain var blockNumber int64 var blockId int64 var err error BeforeEach(func() { + blockChain = fakes.NewMockBlockChain() blockNumber = erc20_watcher.DaiConfig.FirstBlock lastBlockNumber := blockNumber + 1 db = test_helpers.CreateNewDatabase() - setLastBlockOnChain(&blockchain, lastBlockNumber) + setLastBlockOnChain(blockChain, lastBlockNumber) blockRepository := repositories.NewBlockRepository(db) @@ -59,7 +60,7 @@ var _ = Describe("Everyblock transformers", func() { It("creates a token_supply record for each block in the given range", func() { initializer := every_block.TokenSupplyTransformerInitializer{Config: erc20_watcher.DaiConfig} - transformer := initializer.NewTokenSupplyTransformer(db, &blockchain) + transformer := initializer.NewTokenSupplyTransformer(db, blockChain) transformer.Execute() var tokenSupplyCount int diff --git a/examples/erc20_watcher/every_block/transformer.go b/examples/erc20_watcher/every_block/transformer.go index 208df4cd..6ca2718b 100644 --- a/examples/erc20_watcher/every_block/transformer.go +++ b/examples/erc20_watcher/every_block/transformer.go @@ -38,7 +38,7 @@ type TokenSupplyTransformerInitializer struct { Config erc20_watcher.ContractConfig } -func (i TokenSupplyTransformerInitializer) NewTokenSupplyTransformer(db *postgres.DB, blockchain core.Blockchain) shared.Transformer { +func (i TokenSupplyTransformerInitializer) NewTokenSupplyTransformer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer { fetcher := NewFetcher(blockchain) repository := TokenSupplyRepository{DB: db} transformer := Transformer{ @@ -74,7 +74,7 @@ func newTransformerError(err error, blockNumber int64, msg string) error { func (t Transformer) Execute() error { var upperBoundBlock int64 - blockchain := t.Fetcher.GetBlockchain() + blockchain := t.Fetcher.GetBlockChain() lastBlock := blockchain.LastBlock().Int64() if t.Config.LastBlock == -1 { diff --git a/examples/erc20_watcher/every_block/transformer_test.go b/examples/erc20_watcher/every_block/transformer_test.go index 41eeb684..a89a5fcc 100644 --- a/examples/erc20_watcher/every_block/transformer_test.go +++ b/examples/erc20_watcher/every_block/transformer_test.go @@ -21,6 +21,7 @@ import ( "github.com/vulcanize/vulcanizedb/examples/erc20_watcher" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" "github.com/vulcanize/vulcanizedb/examples/mocks" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "math/big" "math/rand" "strconv" @@ -40,7 +41,7 @@ var _ = Describe("Everyblock transformer", func() { var fetcher mocks.Fetcher var repository mocks.TotalSupplyRepository var transformer every_block.Transformer - var blockchain mocks.Blockchain + var blockChain *fakes.MockBlockChain var initialSupply = "27647235749155415536952630" var initialSupplyPlusOne = "27647235749155415536952631" var initialSupplyPlusTwo = "27647235749155415536952632" @@ -48,9 +49,9 @@ var _ = Describe("Everyblock transformer", func() { var defaultLastBlock = big.Int{} BeforeEach(func() { - blockchain = mocks.Blockchain{} - blockchain.SetLastBlock(&defaultLastBlock) - fetcher = mocks.Fetcher{Blockchain: &blockchain} + blockChain = fakes.NewMockBlockChain() + blockChain.SetLastBlock(&defaultLastBlock) + fetcher = mocks.Fetcher{BlockChain: blockChain} fetcher.SetSupply(initialSupply) repository = mocks.TotalSupplyRepository{} repository.SetMissingBlocks([]int64{config.FirstBlock}) @@ -132,7 +133,7 @@ var _ = Describe("Everyblock transformer", func() { mostRecentBlock := big.Int{} mostRecentBlock.SetString(numberToString, 10) - blockchain.SetLastBlock(&mostRecentBlock) + blockChain.SetLastBlock(&mostRecentBlock) err := transformer.Execute() Expect(err).NotTo(HaveOccurred()) @@ -149,13 +150,14 @@ var _ = Describe("Everyblock transformer", func() { } err := transformer.Execute() Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("TestError")) + Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) Expect(err.Error()).To(ContainSubstring("fetching missing blocks")) }) - It("returns an error if the call to the blockchain fails", func() { - failureBlockchain := mocks.FailureBlockchain{} + It("returns an error if the call to the blockChain fails", func() { + failureBlockchain := fakes.NewMockBlockChain() failureBlockchain.SetLastBlock(&defaultLastBlock) + failureBlockchain.SetFetchContractDataErr(fakes.FakeError) fetcher := every_block.NewFetcher(failureBlockchain) transformer = every_block.Transformer{ Fetcher: &fetcher, @@ -163,7 +165,7 @@ var _ = Describe("Everyblock transformer", func() { } err := transformer.Execute() Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("TestError")) + Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) Expect(err.Error()).To(ContainSubstring("supply")) }) @@ -178,7 +180,7 @@ var _ = Describe("Everyblock transformer", func() { } err := transformer.Execute() Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("TestError")) + Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) Expect(err.Error()).To(ContainSubstring("supply")) }) }) diff --git a/examples/mocks/mocks.go b/examples/mocks/mocks.go index 307986dc..b2944170 100644 --- a/examples/mocks/mocks.go +++ b/examples/mocks/mocks.go @@ -15,19 +15,18 @@ package mocks import ( - "errors" + "math/big" + "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" "github.com/vulcanize/vulcanizedb/pkg/core" - "math/big" + "github.com/vulcanize/vulcanizedb/pkg/fakes" ) -var TestError = errors.New("TestError") - type Fetcher struct { ContractAddress string Abi string FetchedBlocks []int64 - Blockchain core.Blockchain + BlockChain core.BlockChain supply big.Int } @@ -35,8 +34,8 @@ func (f *Fetcher) SetSupply(supply string) { f.supply.SetString(supply, 10) } -func (f Fetcher) GetBlockchain() core.Blockchain { - return f.Blockchain +func (f Fetcher) GetBlockChain() core.BlockChain { + return f.BlockChain } func (f *Fetcher) FetchSupplyOf(contractAbi string, contractAddress string, blockNumber int64) (big.Int, error) { @@ -80,7 +79,7 @@ type FailureRepository struct { func (fr *FailureRepository) Create(supply every_block.TokenSupply) error { if fr.createFail { - return TestError + return fakes.FakeError } else { return nil } @@ -88,7 +87,7 @@ func (fr *FailureRepository) Create(supply every_block.TokenSupply) error { func (fr *FailureRepository) MissingBlocks(startingBlock int64, highestBlock int64) ([]int64, error) { if fr.missingBlocksFail { - return []int64{}, TestError + return []int64{}, fakes.FakeError } else { return fr.missingBlocksNumbers, nil } @@ -105,79 +104,3 @@ func (fr *FailureRepository) SetMissingBlocksFail(fail bool) { func (fr *FailureRepository) SetMissingBlocks(missingBlocks []int64) { fr.missingBlocksNumbers = missingBlocks } - -type Blockchain struct { - FetchedAbi string - FetchedContractAddress string - FetchedMethod string - FetchedMethodArg interface{} - FetchedResult interface{} - FetchedBlockNumber int64 - lastBlock *big.Int -} - -func (fb *Blockchain) GetHeaderByNumber(blockNumber int64) (core.Header, error) { - panic("implement me") -} - -func (fb *Blockchain) FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error { - fb.FetchedAbi = abiJSON - fb.FetchedContractAddress = address - fb.FetchedMethod = method - fb.FetchedMethodArg = methodArg - fb.FetchedResult = result - fb.FetchedBlockNumber = blockNumber - return nil -} - -func (fb *Blockchain) GetBlockByNumber(blockNumber int64) (core.Block, error) { - panic("implement me") -} - -func (fb *Blockchain) GetLogs(contract core.Contract, startingBlockNumber *big.Int, endingBlockNumber *big.Int) ([]core.Log, error) { - panic("implement me") -} - -func (fb *Blockchain) LastBlock() *big.Int { - return fb.lastBlock -} - -func (fb *Blockchain) Node() core.Node { - panic("implement me") -} - -func (fb *Blockchain) SetLastBlock(lastBlock *big.Int) { - fb.lastBlock = lastBlock -} - -type FailureBlockchain struct { - lastBlock *big.Int -} - -func (fb FailureBlockchain) GetHeaderByNumber(blockNumber int64) (core.Header, error) { - panic("implement me") -} - -func (FailureBlockchain) FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error { - return errors.New("TestError") -} - -func (FailureBlockchain) GetBlockByNumber(blockNumber int64) (core.Block, error) { - panic("implement me") -} - -func (FailureBlockchain) GetLogs(contract core.Contract, startingBlockNumber *big.Int, endingBlockNumber *big.Int) ([]core.Log, error) { - panic("implement me") -} - -func (fb FailureBlockchain) LastBlock() *big.Int { - return fb.lastBlock -} - -func (FailureBlockchain) Node() core.Node { - panic("implement me") -} - -func (fb *FailureBlockchain) SetLastBlock(lastBlock *big.Int) { - fb.lastBlock = lastBlock -} diff --git a/integration_test/block_rewards_test.go b/integration_test/block_rewards_test.go index ff4361ea..c4a09de0 100644 --- a/integration_test/block_rewards_test.go +++ b/integration_test/block_rewards_test.go @@ -5,9 +5,10 @@ import ( "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" - rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" + vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" "github.com/vulcanize/vulcanizedb/test_config" ) @@ -15,16 +16,13 @@ import ( var _ = Describe("Rewards calculations", func() { It("calculates a block reward for a real block", func() { - rpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) + rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: test_config.InfuraClient.IPCPath, - } - node := node.MakeNode(clientWrapper) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + rpcClient := client.NewRpcClient(rawRpcClient, test_config.InfuraClient.IPCPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) + transactionConverter := vRpc.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) block, err := blockChain.GetBlockByNumber(1071819) Expect(err).ToNot(HaveOccurred()) @@ -32,16 +30,13 @@ var _ = Describe("Rewards calculations", func() { }) It("calculates an uncle reward for a real block", func() { - rpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) + rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: test_config.InfuraClient.IPCPath, - } - node := node.MakeNode(clientWrapper) - transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + rpcClient := client.NewRpcClient(rawRpcClient, test_config.InfuraClient.IPCPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) + transactionConverter := vRpc.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) block, err := blockChain.GetBlockByNumber(1071819) Expect(err).ToNot(HaveOccurred()) diff --git a/integration_test/contract_test.go b/integration_test/contract_test.go index ae07ada4..ad204edb 100644 --- a/integration_test/contract_test.go +++ b/integration_test/contract_test.go @@ -32,15 +32,12 @@ var _ = Describe("Reading contracts", func() { }, Index: 19, Data: "0x0000000000000000000000000000000000000000000000000c7d713b49da0000"} - rpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) + rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: test_config.InfuraClient.IPCPath, - } - node := node.MakeNode(clientWrapper) + rpcClient := client.NewRpcClient(rawRpcClient, test_config.InfuraClient.IPCPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) contract := testing.SampleContract() @@ -53,15 +50,12 @@ var _ = Describe("Reading contracts", func() { }) It("returns and empty log array when no events for a given block / contract combo", func() { - rpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) + rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: test_config.InfuraClient.IPCPath, - } - node := node.MakeNode(clientWrapper) + rpcClient := client.NewRpcClient(rawRpcClient, test_config.InfuraClient.IPCPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) @@ -75,15 +69,12 @@ var _ = Describe("Reading contracts", func() { Describe("Fetching Contract data", func() { It("returns the correct attribute for a real contract", func() { - rpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) + rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: test_config.InfuraClient.IPCPath, - } - node := node.MakeNode(clientWrapper) + rpcClient := client.NewRpcClient(rawRpcClient, test_config.InfuraClient.IPCPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter) diff --git a/integration_test/geth_blockchain_test.go b/integration_test/geth_blockchain_test.go index 91e57fd3..9dc386eb 100644 --- a/integration_test/geth_blockchain_test.go +++ b/integration_test/geth_blockchain_test.go @@ -6,7 +6,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/inmemory" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" @@ -17,29 +17,24 @@ import ( var _ = Describe("Reading from the Geth blockchain", func() { var blockChain *geth.BlockChain - var inMemory *inmemory.InMemory BeforeEach(func() { - rpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) + rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath) Expect(err).NotTo(HaveOccurred()) - ethClient := ethclient.NewClient(rpcClient) - blockChainClient := client.NewClient(ethClient) - clientWrapper := node.ClientWrapper{ - ContextCaller: rpcClient, - IPCPath: test_config.InfuraClient.IPCPath, - } - node := node.MakeNode(clientWrapper) + rpcClient := client.NewRpcClient(rawRpcClient, test_config.InfuraClient.IPCPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + node := node.MakeNode(rpcClient) transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) blockChain = geth.NewBlockChain(blockChainClient, node, transactionConverter) - inMemory = inmemory.NewInMemory() }) It("reads two blocks", func(done Done) { - blocks := &inmemory.BlockRepository{InMemory: inMemory} + blocks := fakes.NewMockBlockRepository() lastBlock := blockChain.LastBlock() queriedBlocks := []int64{lastBlock.Int64() - 5, lastBlock.Int64() - 6} history.RetrieveAndUpdateBlocks(blockChain, blocks, queriedBlocks) - Expect(blocks.BlockCount()).To(Equal(2)) + blocks.AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(2, []int64{lastBlock.Int64() - 5, lastBlock.Int64() - 6}) close(done) }, 30) diff --git a/libraries/shared/transformer_interface.go b/libraries/shared/transformer_interface.go index 6a0c753a..a2fa6675 100644 --- a/libraries/shared/transformer_interface.go +++ b/libraries/shared/transformer_interface.go @@ -10,7 +10,7 @@ type Transformer interface { Execute() error } -type TransformerInitializer func(db *postgres.DB, blockchain core.Blockchain) Transformer +type TransformerInitializer func(db *postgres.DB, blockchain core.BlockChain) Transformer func HexToInt64(byteString string) int64 { value := common.HexToHash(byteString) diff --git a/libraries/shared/watcher.go b/libraries/shared/watcher.go index 5132bee3..1a5cd668 100644 --- a/libraries/shared/watcher.go +++ b/libraries/shared/watcher.go @@ -8,7 +8,7 @@ import ( type Watcher struct { Transformers []Transformer DB postgres.DB - Blockchain core.Blockchain + Blockchain core.BlockChain } func (watcher *Watcher) AddTransformers(us []TransformerInitializer) { diff --git a/libraries/shared/watcher_test.go b/libraries/shared/watcher_test.go index 729c4908..7add85d5 100644 --- a/libraries/shared/watcher_test.go +++ b/libraries/shared/watcher_test.go @@ -23,7 +23,7 @@ func (mh *MockTransformer) Execute() error { return nil } -func fakeTransformerInitializer(db *postgres.DB, blockchain core.Blockchain) shared.Transformer { +func fakeTransformerInitializer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer { return &MockTransformer{} } diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 07b6e3fc..fb56e96a 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -2,7 +2,7 @@ package core import "math/big" -type Blockchain interface { +type BlockChain interface { ContractDataFetcher GetBlockByNumber(blockNumber int64) (Block, error) GetHeaderByNumber(blockNumber int64) (Header, error) diff --git a/pkg/core/client.go b/pkg/core/eth_client.go similarity index 62% rename from pkg/core/client.go rename to pkg/core/eth_client.go index f628e71d..186f222d 100644 --- a/pkg/core/client.go +++ b/pkg/core/eth_client.go @@ -5,12 +5,15 @@ import ( "math/big" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) -type Client interface { +type EthClient interface { BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) + TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) + TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) } diff --git a/pkg/core/rpc_client.go b/pkg/core/rpc_client.go new file mode 100644 index 00000000..d8b99354 --- /dev/null +++ b/pkg/core/rpc_client.go @@ -0,0 +1,9 @@ +package core + +import "context" + +type RpcClient interface { + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + IpcPath() string + SupportedModules() (map[string]string, error) +} diff --git a/pkg/datastore/inmemory/block_repository.go b/pkg/datastore/inmemory/block_repository.go deleted file mode 100644 index ee07efd2..00000000 --- a/pkg/datastore/inmemory/block_repository.go +++ /dev/null @@ -1,51 +0,0 @@ -package inmemory - -import ( - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore" -) - -type BlockRepository struct { - *InMemory -} - -func (blockRepository *BlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) { - blockRepository.CreateOrUpdateBlockCallCount++ - blockRepository.blocks[block.Number] = block - for _, transaction := range block.Transactions { - blockRepository.receipts[transaction.Hash] = transaction.Receipt - blockRepository.logs[transaction.TxHash] = transaction.Logs - } - return 0, nil -} - -func (blockRepository *BlockRepository) GetBlock(blockNumber int64) (core.Block, error) { - if block, ok := blockRepository.blocks[blockNumber]; ok { - return block, nil - } - return core.Block{}, datastore.ErrBlockDoesNotExist(blockNumber) -} - -func (blockRepository *BlockRepository) MissingBlockNumbers(startingBlockNumber int64, endingBlockNumber int64, nodeId string) []int64 { - missingNumbers := []int64{} - for blockNumber := int64(startingBlockNumber); blockNumber <= endingBlockNumber; blockNumber++ { - if _, ok := blockRepository.blocks[blockNumber]; !ok { - missingNumbers = append(missingNumbers, blockNumber) - } - } - return missingNumbers -} - -func (blockRepository *BlockRepository) SetBlocksStatus(chainHead int64) { - for key, block := range blockRepository.blocks { - if key < (chainHead - blocksFromHeadBeforeFinal) { - tmp := block - tmp.IsFinal = true - blockRepository.blocks[key] = tmp - } - } -} - -func (blockRepository *BlockRepository) BlockCount() int { - return len(blockRepository.blocks) -} diff --git a/pkg/datastore/inmemory/contract_repository.go b/pkg/datastore/inmemory/contract_repository.go deleted file mode 100644 index 6f759fd7..00000000 --- a/pkg/datastore/inmemory/contract_repository.go +++ /dev/null @@ -1,35 +0,0 @@ -package inmemory - -import ( - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore" -) - -type ContractRepostiory struct { - *InMemory -} - -func (contractRepository *ContractRepostiory) ContractExists(contractHash string) bool { - _, present := contractRepository.contracts[contractHash] - return present -} - -func (contractRepository *ContractRepostiory) GetContract(contractHash string) (core.Contract, error) { - contract, ok := contractRepository.contracts[contractHash] - if !ok { - return core.Contract{}, datastore.ErrContractDoesNotExist(contractHash) - } - for _, block := range contractRepository.blocks { - for _, transaction := range block.Transactions { - if transaction.To == contractHash { - contract.Transactions = append(contract.Transactions, transaction) - } - } - } - return contract, nil -} - -func (contractRepository *ContractRepostiory) CreateContract(contract core.Contract) error { - contractRepository.contracts[contract.Hash] = contract - return nil -} diff --git a/pkg/datastore/inmemory/header_repository.go b/pkg/datastore/inmemory/header_repository.go deleted file mode 100644 index ba78a1d5..00000000 --- a/pkg/datastore/inmemory/header_repository.go +++ /dev/null @@ -1,30 +0,0 @@ -package inmemory - -import "github.com/vulcanize/vulcanizedb/pkg/core" - -type HeaderRepository struct { - memory *InMemory -} - -func NewHeaderRepository(memory *InMemory) *HeaderRepository { - return &HeaderRepository{memory: memory} -} - -func (repository *HeaderRepository) CreateOrUpdateHeader(header core.Header) (int64, error) { - repository.memory.headers[header.BlockNumber] = header - return 0, nil -} - -func (repository *HeaderRepository) GetHeader(blockNumber int64) (core.Header, error) { - return repository.memory.headers[blockNumber], nil -} - -func (repository *HeaderRepository) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) []int64 { - missingNumbers := []int64{} - for blockNumber := int64(startingBlockNumber); blockNumber <= endingBlockNumber; blockNumber++ { - if _, ok := repository.memory.headers[blockNumber]; !ok { - missingNumbers = append(missingNumbers, blockNumber) - } - } - return missingNumbers -} diff --git a/pkg/datastore/inmemory/in_memory.go b/pkg/datastore/inmemory/in_memory.go deleted file mode 100644 index d7d9d87a..00000000 --- a/pkg/datastore/inmemory/in_memory.go +++ /dev/null @@ -1,32 +0,0 @@ -package inmemory - -import ( - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/filters" -) - -const ( - blocksFromHeadBeforeFinal = 20 -) - -type InMemory struct { - CreateOrUpdateBlockCallCount int - blocks map[int64]core.Block - contracts map[string]core.Contract - headers map[int64]core.Header - logFilters map[string]filters.LogFilter - logs map[string][]core.Log - receipts map[string]core.Receipt -} - -func NewInMemory() *InMemory { - return &InMemory{ - CreateOrUpdateBlockCallCount: 0, - blocks: make(map[int64]core.Block), - contracts: make(map[string]core.Contract), - headers: make(map[int64]core.Header), - logFilters: make(map[string]filters.LogFilter), - logs: make(map[string][]core.Log), - receipts: make(map[string]core.Receipt), - } -} diff --git a/pkg/fakes/mock_block_repository.go b/pkg/fakes/mock_block_repository.go index 6391c198..7c05bfc0 100644 --- a/pkg/fakes/mock_block_repository.go +++ b/pkg/fakes/mock_block_repository.go @@ -7,14 +7,16 @@ import ( ) type MockBlockRepository struct { + createOrUpdateBlockCallCount int createOrUpdateBlockCalled bool createOrUpdateBlockPassedBlock core.Block - createOrUpdateBlockReturnInt int64 + createOrUpdateBlockPassedBlockNumbers []int64 createOrUpdateBlockReturnErr error + createOrUpdateBlockReturnInt int64 missingBlockNumbersCalled bool - missingBlockNumbersPassedStartingBlockNumber int64 missingBlockNumbersPassedEndingBlockNumber int64 missingBlockNumbersPassedNodeId string + missingBlockNumbersPassedStartingBlockNumber int64 missingBlockNumbersReturnArray []int64 setBlockStatusCalled bool setBlockStatusPassedChainHead int64 @@ -22,65 +24,78 @@ type MockBlockRepository struct { func NewMockBlockRepository() *MockBlockRepository { return &MockBlockRepository{ + createOrUpdateBlockCallCount: 0, createOrUpdateBlockCalled: false, createOrUpdateBlockPassedBlock: core.Block{}, - createOrUpdateBlockReturnInt: 0, + createOrUpdateBlockPassedBlockNumbers: nil, createOrUpdateBlockReturnErr: nil, + createOrUpdateBlockReturnInt: 0, missingBlockNumbersCalled: false, - missingBlockNumbersPassedStartingBlockNumber: 0, missingBlockNumbersPassedEndingBlockNumber: 0, missingBlockNumbersPassedNodeId: "", + missingBlockNumbersPassedStartingBlockNumber: 0, missingBlockNumbersReturnArray: nil, setBlockStatusCalled: false, setBlockStatusPassedChainHead: 0, } } -func (mbr *MockBlockRepository) SetCreateOrUpdateBlockReturnVals(i int64, err error) { - mbr.createOrUpdateBlockReturnInt = i - mbr.createOrUpdateBlockReturnErr = err +func (repository *MockBlockRepository) SetCreateOrUpdateBlockReturnVals(i int64, err error) { + repository.createOrUpdateBlockReturnInt = i + repository.createOrUpdateBlockReturnErr = err } -func (mbr *MockBlockRepository) SetMissingBlockNumbersReturnArray(returnArray []int64) { - mbr.missingBlockNumbersReturnArray = returnArray +func (repository *MockBlockRepository) SetMissingBlockNumbersReturnArray(returnArray []int64) { + repository.missingBlockNumbersReturnArray = returnArray } -func (mbr *MockBlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) { - mbr.createOrUpdateBlockCalled = true - mbr.createOrUpdateBlockPassedBlock = block - return mbr.createOrUpdateBlockReturnInt, mbr.createOrUpdateBlockReturnErr +func (repository *MockBlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) { + repository.createOrUpdateBlockCallCount++ + repository.createOrUpdateBlockCalled = true + repository.createOrUpdateBlockPassedBlock = block + repository.createOrUpdateBlockPassedBlockNumbers = append(repository.createOrUpdateBlockPassedBlockNumbers, block.Number) + return repository.createOrUpdateBlockReturnInt, repository.createOrUpdateBlockReturnErr } -func (mbr *MockBlockRepository) GetBlock(blockNumber int64) (core.Block, error) { - panic("implement me") +func (repository *MockBlockRepository) GetBlock(blockNumber int64) (core.Block, error) { + return core.Block{Number: blockNumber}, nil } -func (mbr *MockBlockRepository) MissingBlockNumbers(startingBlockNumber int64, endingBlockNumber int64, nodeId string) []int64 { - mbr.missingBlockNumbersCalled = true - mbr.missingBlockNumbersPassedStartingBlockNumber = startingBlockNumber - mbr.missingBlockNumbersPassedEndingBlockNumber = endingBlockNumber - mbr.missingBlockNumbersPassedNodeId = nodeId - return mbr.missingBlockNumbersReturnArray +func (repository *MockBlockRepository) MissingBlockNumbers(startingBlockNumber int64, endingBlockNumber int64, nodeId string) []int64 { + repository.missingBlockNumbersCalled = true + repository.missingBlockNumbersPassedStartingBlockNumber = startingBlockNumber + repository.missingBlockNumbersPassedEndingBlockNumber = endingBlockNumber + repository.missingBlockNumbersPassedNodeId = nodeId + return repository.missingBlockNumbersReturnArray } -func (mbr *MockBlockRepository) SetBlocksStatus(chainHead int64) { - mbr.setBlockStatusCalled = true - mbr.setBlockStatusPassedChainHead = chainHead +func (repository *MockBlockRepository) SetBlocksStatus(chainHead int64) { + repository.setBlockStatusCalled = true + repository.setBlockStatusPassedChainHead = chainHead } -func (mbr *MockBlockRepository) AssertCreateOrUpdateBlockCalledWith(block core.Block) { - Expect(mbr.createOrUpdateBlockCalled).To(BeTrue()) - Expect(mbr.createOrUpdateBlockPassedBlock).To(Equal(block)) +func (repository *MockBlockRepository) AssertCreateOrUpdateBlockCallCountEquals(times int) { + Expect(repository.createOrUpdateBlockCallCount).To(Equal(times)) } -func (mbr *MockBlockRepository) AssertMissingBlockNumbersCalledWith(startingBlockNumber int64, endingBlockNumber int64, nodeId string) { - Expect(mbr.missingBlockNumbersCalled).To(BeTrue()) - Expect(mbr.missingBlockNumbersPassedStartingBlockNumber).To(Equal(startingBlockNumber)) - Expect(mbr.missingBlockNumbersPassedEndingBlockNumber).To(Equal(endingBlockNumber)) - Expect(mbr.missingBlockNumbersPassedNodeId).To(Equal(nodeId)) +func (repository *MockBlockRepository) AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(times int, blockNumbers []int64) { + Expect(repository.createOrUpdateBlockCallCount).To(Equal(times)) + Expect(repository.createOrUpdateBlockPassedBlockNumbers).To(Equal(blockNumbers)) } -func (mbr *MockBlockRepository) AssertSetBlockStatusCalledWith(chainHead int64) { - Expect(mbr.setBlockStatusCalled).To(BeTrue()) - Expect(mbr.setBlockStatusPassedChainHead).To(Equal(chainHead)) +func (repository *MockBlockRepository) AssertCreateOrUpdateBlockCalledWith(block core.Block) { + Expect(repository.createOrUpdateBlockCalled).To(BeTrue()) + Expect(repository.createOrUpdateBlockPassedBlock).To(Equal(block)) +} + +func (repository *MockBlockRepository) AssertMissingBlockNumbersCalledWith(startingBlockNumber int64, endingBlockNumber int64, nodeId string) { + Expect(repository.missingBlockNumbersCalled).To(BeTrue()) + Expect(repository.missingBlockNumbersPassedStartingBlockNumber).To(Equal(startingBlockNumber)) + Expect(repository.missingBlockNumbersPassedEndingBlockNumber).To(Equal(endingBlockNumber)) + Expect(repository.missingBlockNumbersPassedNodeId).To(Equal(nodeId)) +} + +func (repository *MockBlockRepository) AssertSetBlockStatusCalledWith(chainHead int64) { + Expect(repository.setBlockStatusCalled).To(BeTrue()) + Expect(repository.setBlockStatusPassedChainHead).To(Equal(chainHead)) } diff --git a/pkg/fakes/mock_blockchain.go b/pkg/fakes/mock_blockchain.go index 5229501c..bd543106 100644 --- a/pkg/fakes/mock_blockchain.go +++ b/pkg/fakes/mock_blockchain.go @@ -3,95 +3,81 @@ package fakes import ( "math/big" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/core" ) type MockBlockChain struct { - ContractReturnValue []byte - WasToldToStop bool - blocks map[int64]core.Block - blocksChannel chan core.Block - contractAttributes map[string]map[string]string - err error - headers map[int64]core.Header - logs map[string][]core.Log - node core.Node + fetchContractDataErr error + fetchContractDataPassedAbi string + fetchContractDataPassedAddress string + fetchContractDataPassedMethod string + fetchContractDataPassedMethodArg interface{} + fetchContractDataPassedResult interface{} + fetchContractDataPassedBlockNumber int64 + getBlockByNumberErr error + lastBlock *big.Int + node core.Node +} + +func NewMockBlockChain() *MockBlockChain { + return &MockBlockChain{ + node: core.Node{GenesisBlock: "GENESIS", NetworkID: 1, ID: "x123", ClientName: "Geth"}, + } +} + +func (blockChain *MockBlockChain) SetFetchContractDataErr(err error) { + blockChain.fetchContractDataErr = err +} + +func (blockChain *MockBlockChain) SetLastBlock(blockNumber *big.Int) { + blockChain.lastBlock = blockNumber +} + +func (blockChain *MockBlockChain) SetGetBlockByNumberErr(err error) { + blockChain.getBlockByNumberErr = err } func (blockChain *MockBlockChain) GetHeaderByNumber(blockNumber int64) (core.Header, error) { - return blockChain.headers[blockNumber], nil + return core.Header{BlockNumber: blockNumber}, nil } func (blockChain *MockBlockChain) FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error { - panic("implement me") + blockChain.fetchContractDataPassedAbi = abiJSON + blockChain.fetchContractDataPassedAddress = address + blockChain.fetchContractDataPassedMethod = method + blockChain.fetchContractDataPassedMethodArg = methodArg + blockChain.fetchContractDataPassedResult = result + blockChain.fetchContractDataPassedBlockNumber = blockNumber + return blockChain.fetchContractDataErr } func (blockChain *MockBlockChain) CallContract(contractHash string, input []byte, blockNumber *big.Int) ([]byte, error) { - return blockChain.ContractReturnValue, nil + return []byte{}, nil } func (blockChain *MockBlockChain) LastBlock() *big.Int { - var max int64 - for blockNumber := range blockChain.blocks { - if blockNumber > max { - max = blockNumber - } - } - return big.NewInt(max) + return blockChain.lastBlock } func (blockChain *MockBlockChain) GetLogs(contract core.Contract, startingBlock *big.Int, endingBlock *big.Int) ([]core.Log, error) { - return blockChain.logs[contract.Hash], nil + return []core.Log{}, nil } func (blockChain *MockBlockChain) Node() core.Node { return blockChain.node } -func NewMockBlockChain(err error) *MockBlockChain { - return &MockBlockChain{ - blocks: make(map[int64]core.Block), - logs: make(map[string][]core.Log), - contractAttributes: make(map[string]map[string]string), - node: core.Node{GenesisBlock: "GENESIS", NetworkID: 1, ID: "x123", ClientName: "Geth"}, - err: err, - } -} - -func NewMockBlockChainWithBlocks(blocks []core.Block) *MockBlockChain { - blockNumberToBlocks := make(map[int64]core.Block) - for _, block := range blocks { - blockNumberToBlocks[block.Number] = block - } - return &MockBlockChain{ - blocks: blockNumberToBlocks, - } -} - -func NewMockBlockChainWithHeaders(headers []core.Header) *MockBlockChain { - // need to create blocks and headers so that LastBlock() will work in the mock - // no reason to implement LastBlock() separately for headers since it checks - // the last header in the Node's DB already - memoryBlocks := make(map[int64]core.Block) - memoryHeaders := make(map[int64]core.Header) - for _, header := range headers { - memoryBlocks[header.BlockNumber] = core.Block{Number: header.BlockNumber} - memoryHeaders[header.BlockNumber] = header - } - return &MockBlockChain{ - blocks: memoryBlocks, - headers: memoryHeaders, - } -} - func (blockChain *MockBlockChain) GetBlockByNumber(blockNumber int64) (core.Block, error) { - if blockChain.err != nil { - return core.Block{}, blockChain.err - } - return blockChain.blocks[blockNumber], nil + return core.Block{Number: blockNumber}, blockChain.getBlockByNumberErr } -func (blockChain *MockBlockChain) AddBlock(block core.Block) { - blockChain.blocks[block.Number] = block - blockChain.blocksChannel <- block +// TODO: handle methodArg being nil (can't match nil to nil in Gomega) +func (blockChain *MockBlockChain) AssertFetchContractDataCalledWith(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) { + Expect(blockChain.fetchContractDataPassedAbi).To(Equal(abiJSON)) + Expect(blockChain.fetchContractDataPassedAddress).To(Equal(address)) + Expect(blockChain.fetchContractDataPassedMethod).To(Equal(method)) + Expect(blockChain.fetchContractDataPassedResult).To(Equal(result)) + Expect(blockChain.fetchContractDataPassedBlockNumber).To(Equal(blockNumber)) } diff --git a/pkg/fakes/mock_client.go b/pkg/fakes/mock_eth_client.go similarity index 52% rename from pkg/fakes/mock_client.go rename to pkg/fakes/mock_eth_client.go index 109bda40..c1e544d3 100644 --- a/pkg/fakes/mock_client.go +++ b/pkg/fakes/mock_eth_client.go @@ -5,11 +5,12 @@ import ( "math/big" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/gomega" ) -type MockClient struct { +type MockEthClient struct { callContractErr error callContractPassedContext context.Context callContractPassedMsg ethereum.CallMsg @@ -27,10 +28,14 @@ type MockClient struct { filterLogsPassedContext context.Context filterLogsPassedQuery ethereum.FilterQuery filterLogsReturnLogs []types.Log + transactionReceipts map[string]*types.Receipt + err error + transactionSenderErr error + transactionReceiptErr error } -func NewMockClient() *MockClient { - return &MockClient{ +func NewMockEthClient() *MockEthClient { + return &MockEthClient{ callContractErr: nil, callContractPassedContext: nil, callContractPassedMsg: ethereum.CallMsg{}, @@ -48,83 +53,110 @@ func NewMockClient() *MockClient { filterLogsPassedContext: nil, filterLogsPassedQuery: ethereum.FilterQuery{}, filterLogsReturnLogs: nil, + transactionReceipts: make(map[string]*types.Receipt), + err: nil, } } -func (client *MockClient) SetCallContractErr(err error) { +func (client *MockEthClient) SetCallContractErr(err error) { client.callContractErr = err } -func (client *MockClient) SetCallContractReturnBytes(returnBytes []byte) { +func (client *MockEthClient) SetCallContractReturnBytes(returnBytes []byte) { client.callContractReturnBytes = returnBytes } -func (client *MockClient) SetBlockByNumberErr(err error) { +func (client *MockEthClient) SetBlockByNumberErr(err error) { client.blockByNumberErr = err } -func (client *MockClient) SetBlockByNumberReturnBlock(block *types.Block) { +func (client *MockEthClient) SetBlockByNumberReturnBlock(block *types.Block) { client.blockByNumberReturnBlock = block } -func (client *MockClient) SetHeaderByNumberErr(err error) { +func (client *MockEthClient) SetHeaderByNumberErr(err error) { client.headerByNumberErr = err } -func (client *MockClient) SetHeaderByNumberReturnHeader(header *types.Header) { +func (client *MockEthClient) SetHeaderByNumberReturnHeader(header *types.Header) { client.headerByNumberReturnHeader = header } -func (client *MockClient) SetFilterLogsErr(err error) { +func (client *MockEthClient) SetFilterLogsErr(err error) { client.filterLogsErr = err } -func (client *MockClient) SetFilterLogsReturnLogs(logs []types.Log) { +func (client *MockEthClient) SetFilterLogsReturnLogs(logs []types.Log) { client.filterLogsReturnLogs = logs } -func (client *MockClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { +func (client *MockEthClient) SetTransactionReceiptErr(err error) { + client.transactionReceiptErr = err +} + +func (client *MockEthClient) SetTransactionReceipts(receipts []*types.Receipt) { + for _, receipt := range receipts { + client.transactionReceipts[receipt.TxHash.Hex()] = receipt + } +} + +func (client *MockEthClient) SetTransactionSenderErr(err error) { + client.transactionSenderErr = err +} + +func (client *MockEthClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { client.callContractPassedContext = ctx client.callContractPassedMsg = msg client.callContractPassedNumber = blockNumber return client.callContractReturnBytes, client.callContractErr } -func (client *MockClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { +func (client *MockEthClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { client.blockByNumberPassedContext = ctx client.blockByNumberPassedNumber = number return client.blockByNumberReturnBlock, client.blockByNumberErr } -func (client *MockClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { +func (client *MockEthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { client.headerByNumberPassedContext = ctx client.headerByNumberPassedNumber = number return client.headerByNumberReturnHeader, client.headerByNumberErr } -func (client *MockClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { +func (client *MockEthClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { client.filterLogsPassedContext = ctx client.filterLogsPassedQuery = q return client.filterLogsReturnLogs, client.filterLogsErr } -func (client *MockClient) AssertCallContractCalledWith(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) { +func (client *MockEthClient) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { + return common.HexToAddress("0x123"), client.transactionSenderErr +} + +func (client *MockEthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + if gasUsed, ok := client.transactionReceipts[txHash.Hex()]; ok { + return gasUsed, client.transactionReceiptErr + } + return &types.Receipt{GasUsed: uint64(0)}, client.transactionReceiptErr +} + +func (client *MockEthClient) AssertCallContractCalledWith(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) { Expect(client.callContractPassedContext).To(Equal(ctx)) Expect(client.callContractPassedMsg).To(Equal(msg)) Expect(client.callContractPassedNumber).To(Equal(blockNumber)) } -func (client *MockClient) AssertBlockByNumberCalledWith(ctx context.Context, number *big.Int) { +func (client *MockEthClient) AssertBlockByNumberCalledWith(ctx context.Context, number *big.Int) { Expect(client.blockByNumberPassedContext).To(Equal(ctx)) Expect(client.blockByNumberPassedNumber).To(Equal(number)) } -func (client *MockClient) AssertHeaderByNumberCalledWith(ctx context.Context, number *big.Int) { +func (client *MockEthClient) AssertHeaderByNumberCalledWith(ctx context.Context, number *big.Int) { Expect(client.headerByNumberPassedContext).To(Equal(ctx)) Expect(client.headerByNumberPassedNumber).To(Equal(number)) } -func (client *MockClient) AssertFilterLogsCalledWith(ctx context.Context, q ethereum.FilterQuery) { +func (client *MockEthClient) AssertFilterLogsCalledWith(ctx context.Context, q ethereum.FilterQuery) { Expect(client.filterLogsPassedContext).To(Equal(ctx)) Expect(client.filterLogsPassedQuery).To(Equal(q)) } diff --git a/pkg/fakes/mock_header_repository.go b/pkg/fakes/mock_header_repository.go new file mode 100644 index 00000000..e5254e9c --- /dev/null +++ b/pkg/fakes/mock_header_repository.go @@ -0,0 +1,40 @@ +package fakes + +import ( + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/core" +) + +type MockHeaderRepository struct { + createOrUpdateBlockNumbersCallCount int + createOrUpdateBlockNumbersPassedBlockNumbers []int64 + missingBlockNumbers []int64 +} + +func NewMockHeaderRepository() *MockHeaderRepository { + return &MockHeaderRepository{} +} + +func (repository *MockHeaderRepository) SetMissingBlockNumbers(blockNumbers []int64) { + repository.missingBlockNumbers = blockNumbers +} + +func (repository *MockHeaderRepository) CreateOrUpdateHeader(header core.Header) (int64, error) { + repository.createOrUpdateBlockNumbersCallCount++ + repository.createOrUpdateBlockNumbersPassedBlockNumbers = append(repository.createOrUpdateBlockNumbersPassedBlockNumbers, header.BlockNumber) + return 0, nil +} + +func (*MockHeaderRepository) GetHeader(blockNumber int64) (core.Header, error) { + return core.Header{BlockNumber: blockNumber}, nil +} + +func (repository *MockHeaderRepository) MissingBlockNumbers(startingBlockNumber, endingBlockNumber int64, nodeID string) []int64 { + return repository.missingBlockNumbers +} + +func (repository *MockHeaderRepository) AssertCreateOrUpdateHeaderCallCountAndPassedBlockNumbers(times int, blockNumbers []int64) { + Expect(repository.createOrUpdateBlockNumbersCallCount).To(Equal(times)) + Expect(repository.createOrUpdateBlockNumbersPassedBlockNumbers).To(Equal(blockNumbers)) +} diff --git a/pkg/fakes/mock_rpc_client.go b/pkg/fakes/mock_rpc_client.go new file mode 100644 index 00000000..d4cbf9b1 --- /dev/null +++ b/pkg/fakes/mock_rpc_client.go @@ -0,0 +1,73 @@ +package fakes + +import ( + "context" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/p2p" + "github.com/vulcanize/vulcanizedb/pkg/core" +) + +type MockRpcClient struct { + ipcPath string + nodeType core.NodeType +} + +func NewMockRpcClient() *MockRpcClient { + return &MockRpcClient{} +} + +func (client *MockRpcClient) SetNodeType(nodeType core.NodeType) { + client.nodeType = nodeType +} + +func (client *MockRpcClient) SetIpcPath(ipcPath string) { + client.ipcPath = ipcPath +} + +func (*MockRpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + switch method { + case "admin_nodeInfo": + if p, ok := result.(*p2p.NodeInfo); ok { + p.ID = "enode://GethNode@172.17.0.1:30303" + p.Name = "Geth/v1.7" + } + case "eth_getBlockByNumber": + if p, ok := result.(*types.Header); ok { + *p = types.Header{} + } + + case "parity_versionInfo": + if p, ok := result.(*core.ParityNodeInfo); ok { + *p = core.ParityNodeInfo{ + Track: "", + ParityVersion: core.ParityVersion{ + Major: 1, + Minor: 2, + Patch: 3, + }, + Hash: "", + } + } + case "parity_enode": + if p, ok := result.(*string); ok { + *p = "enode://ParityNode@172.17.0.1:30303" + } + case "net_version": + if p, ok := result.(*string); ok { + *p = "1234" + } + } + return nil +} + +func (client *MockRpcClient) IpcPath() string { + return client.ipcPath +} + +func (client *MockRpcClient) SupportedModules() (map[string]string, error) { + result := make(map[string]string) + if client.nodeType == core.GETH { + result["admin"] = "ok" + } + return result, nil +} diff --git a/pkg/geth/blockchain.go b/pkg/geth/blockchain.go index 2351a777..a6d9193d 100644 --- a/pkg/geth/blockchain.go +++ b/pkg/geth/blockchain.go @@ -12,13 +12,13 @@ import ( ) type BlockChain struct { - client core.Client + client core.EthClient blockConverter vulcCommon.BlockConverter headerConverter vulcCommon.HeaderConverter node core.Node } -func NewBlockChain(client core.Client, node core.Node, converter vulcCommon.TransactionConverter) *BlockChain { +func NewBlockChain(client core.EthClient, node core.Node, converter vulcCommon.TransactionConverter) *BlockChain { return &BlockChain{ client: client, blockConverter: vulcCommon.NewBlockConverter(converter), diff --git a/pkg/geth/blockchain_test.go b/pkg/geth/blockchain_test.go index 2bb207d0..69f04e3b 100644 --- a/pkg/geth/blockchain_test.go +++ b/pkg/geth/blockchain_test.go @@ -19,7 +19,7 @@ import ( var _ = Describe("Geth blockchain", func() { Describe("getting a block", func() { It("fetches block from client", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() mockClient.SetBlockByNumberReturnBlock(types.NewBlockWithHeader(&types.Header{})) node := vulcCore.Node{} blockChain := geth.NewBlockChain(mockClient, node, cold_db.NewColdDbTransactionConverter()) @@ -32,7 +32,7 @@ var _ = Describe("Geth blockchain", func() { }) It("returns err if client returns err", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() mockClient.SetBlockByNumberErr(fakes.FakeError) node := vulcCore.Node{} blockChain := geth.NewBlockChain(mockClient, node, cold_db.NewColdDbTransactionConverter()) @@ -46,7 +46,7 @@ var _ = Describe("Geth blockchain", func() { Describe("getting a header", func() { It("fetches header from client", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() blockNumber := int64(100) mockClient.SetHeaderByNumberReturnHeader(&types.Header{Number: big.NewInt(blockNumber)}) node := vulcCore.Node{} @@ -59,7 +59,7 @@ var _ = Describe("Geth blockchain", func() { }) It("returns err if client returns err", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() mockClient.SetHeaderByNumberErr(fakes.FakeError) node := vulcCore.Node{} blockChain := geth.NewBlockChain(mockClient, node, cold_db.NewColdDbTransactionConverter()) @@ -73,7 +73,7 @@ var _ = Describe("Geth blockchain", func() { Describe("getting logs", func() { It("fetches logs from client", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() mockClient.SetFilterLogsReturnLogs([]types.Log{{}}) node := vulcCore.Node{} blockChain := geth.NewBlockChain(mockClient, node, cold_db.NewColdDbTransactionConverter()) @@ -93,7 +93,7 @@ var _ = Describe("Geth blockchain", func() { }) It("returns err if client returns err", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() mockClient.SetFilterLogsErr(fakes.FakeError) node := vulcCore.Node{} blockChain := geth.NewBlockChain(mockClient, node, cold_db.NewColdDbTransactionConverter()) @@ -110,7 +110,7 @@ var _ = Describe("Geth blockchain", func() { Describe("getting the most recent block number", func() { It("fetches latest header from client", func() { - mockClient := fakes.NewMockClient() + mockClient := fakes.NewMockEthClient() blockNumber := int64(100) mockClient.SetHeaderByNumberReturnHeader(&types.Header{Number: big.NewInt(blockNumber)}) node := vulcCore.Node{} diff --git a/pkg/geth/client/client.go b/pkg/geth/client/client.go deleted file mode 100644 index d98f631f..00000000 --- a/pkg/geth/client/client.go +++ /dev/null @@ -1,33 +0,0 @@ -package client - -import ( - "context" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "math/big" -) - -type Client struct { - client *ethclient.Client -} - -func NewClient(client *ethclient.Client) Client { - return Client{client: client} -} - -func (client Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { - return client.client.BlockByNumber(ctx, number) -} - -func (client Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - return client.client.CallContract(ctx, msg, blockNumber) -} - -func (client Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { - return client.client.FilterLogs(ctx, q) -} - -func (client Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { - return client.client.HeaderByNumber(ctx, number) -} diff --git a/pkg/geth/client/eth_client.go b/pkg/geth/client/eth_client.go new file mode 100644 index 00000000..21b7cd3d --- /dev/null +++ b/pkg/geth/client/eth_client.go @@ -0,0 +1,42 @@ +package client + +import ( + "context" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "math/big" +) + +type EthClient struct { + client *ethclient.Client +} + +func NewEthClient(client *ethclient.Client) EthClient { + return EthClient{client: client} +} + +func (client EthClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { + return client.client.BlockByNumber(ctx, number) +} + +func (client EthClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + return client.client.CallContract(ctx, msg, blockNumber) +} + +func (client EthClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return client.client.FilterLogs(ctx, q) +} + +func (client EthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + return client.client.HeaderByNumber(ctx, number) +} + +func (client EthClient) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { + return client.client.TransactionSender(ctx, tx, block, index) +} + +func (client EthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + return client.client.TransactionReceipt(ctx, txHash) +} diff --git a/pkg/geth/client/rpc_client.go b/pkg/geth/client/rpc_client.go new file mode 100644 index 00000000..46b3f80f --- /dev/null +++ b/pkg/geth/client/rpc_client.go @@ -0,0 +1,30 @@ +package client + +import ( + "context" + "github.com/ethereum/go-ethereum/rpc" +) + +type RpcClient struct { + client *rpc.Client + ipcPath string +} + +func NewRpcClient(client *rpc.Client, ipcPath string) RpcClient { + return RpcClient{ + client: client, + ipcPath: ipcPath, + } +} + +func (client RpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + return client.client.CallContext(ctx, result, method, args) +} + +func (client RpcClient) IpcPath() string { + return client.ipcPath +} + +func (client RpcClient) SupportedModules() (map[string]string, error) { + return client.client.SupportedModules() +} diff --git a/pkg/geth/converters/common/block_converter_test.go b/pkg/geth/converters/common/block_converter_test.go index 3e5d358c..ba05826b 100644 --- a/pkg/geth/converters/common/block_converter_test.go +++ b/pkg/geth/converters/common/block_converter_test.go @@ -1,8 +1,6 @@ package common_test import ( - "context" - "fmt" "io/ioutil" "log" "math/big" @@ -14,57 +12,11 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/fakes" vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common" "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" ) -type FakeGethClient struct { - receipts map[string]*types.Receipt - err error -} - -type TransActionReceiptError struct{} - -func (tarErr TransActionReceiptError) Error() string { - return fmt.Sprintf("transaction receipt error") -} - -type TransactionSenderError struct{} - -func (tasErr TransactionSenderError) Error() string { - return fmt.Sprintf("transaction sender error") -} - -func NewFakeClient(err error) *FakeGethClient { - return &FakeGethClient{ - receipts: make(map[string]*types.Receipt), - err: err, - } -} - -func (client *FakeGethClient) AddReceipts(receipts []*types.Receipt) { - for _, receipt := range receipts { - client.receipts[receipt.TxHash.Hex()] = receipt - } -} - -func (client *FakeGethClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - if err, ok := client.err.(TransActionReceiptError); ok { - return &types.Receipt{}, err - } - if gasUsed, ok := client.receipts[txHash.Hex()]; ok { - return gasUsed, nil - } - return &types.Receipt{GasUsed: uint64(0)}, nil -} - -func (client *FakeGethClient) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { - if err, ok := client.err.(TransactionSenderError); ok { - return common.Address{}, err - } - return common.HexToAddress("0x123"), nil -} - var _ = Describe("Conversion of GethBlock to core.Block", func() { It("converts basic Block metadata", func() { @@ -90,7 +42,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { UncleHash: common.Hash{128}, } block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{}) - client := &FakeGethClient{} + client := fakes.NewMockEthClient() transactionConverter := rpc.NewRpcTransactionConverter(client) blockConverter := vulcCommon.NewBlockConverter(transactionConverter) @@ -132,8 +84,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { } receipts := []*types.Receipt{&receipt} - client := NewFakeClient(nil) - client.AddReceipts(receipts) + client := fakes.NewMockEthClient() + client.SetTransactionReceipts(receipts) number := int64(1071819) header := types.Header{ @@ -176,8 +128,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { } block := types.NewBlock(&header, transactions, uncles, receipts) - client := NewFakeClient(nil) - client.AddReceipts(receipts) + client := fakes.NewMockEthClient() + client.SetTransactionReceipts(receipts) transactionConverter := rpc.NewRpcTransactionConverter(client) blockConverter := vulcCommon.NewBlockConverter(transactionConverter) @@ -225,8 +177,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { var uncles []*types.Header block := types.NewBlock(&header, transactions, uncles, receipts) - client := NewFakeClient(nil) - client.AddReceipts(receipts) + client := fakes.NewMockEthClient() + client.SetTransactionReceipts(receipts) transactionConverter := rpc.NewRpcTransactionConverter(client) blockConverter := vulcCommon.NewBlockConverter(transactionConverter) @@ -241,7 +193,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { It("is empty", func() { header := types.Header{} block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{}) - client := &FakeGethClient{} + client := fakes.NewMockEthClient() transactionConverter := rpc.NewRpcTransactionConverter(client) blockConverter := vulcCommon.NewBlockConverter(transactionConverter) @@ -270,8 +222,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { TxHash: gethTransaction.Hash(), } - client := NewFakeClient(nil) - client.AddReceipts([]*types.Receipt{gethReceipt}) + client := fakes.NewMockEthClient() + client.SetTransactionReceipts([]*types.Receipt{gethReceipt}) header := types.Header{} block := types.NewBlock( @@ -317,8 +269,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { ContractAddress: common.HexToAddress("0x1023342345"), } - client := NewFakeClient(nil) - client.AddReceipts([]*types.Receipt{gethReceipt}) + client := fakes.NewMockEthClient() + client.SetTransactionReceipts([]*types.Receipt{gethReceipt}) block := types.NewBlock( &types.Header{}, @@ -373,25 +325,25 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { }) It("returns an error when transaction sender call fails", func() { - client := NewFakeClient(TransactionSenderError{}) - client.AddReceipts([]*types.Receipt{}) + client := fakes.NewMockEthClient() + client.SetTransactionSenderErr(fakes.FakeError) transactionConverter := rpc.NewRpcTransactionConverter(client) blockConverter := vulcCommon.NewBlockConverter(transactionConverter) _, err := blockConverter.ToCoreBlock(block) - Expect(err).To(Equal(TransactionSenderError{})) + Expect(err).To(MatchError(fakes.FakeError)) }) It("returns an error when transaction receipt call fails", func() { - client := NewFakeClient(TransActionReceiptError{}) - client.AddReceipts([]*types.Receipt{}) + client := fakes.NewMockEthClient() + client.SetTransactionReceiptErr(fakes.FakeError) transactionConverter := rpc.NewRpcTransactionConverter(client) blockConverter := vulcCommon.NewBlockConverter(transactionConverter) _, err := blockConverter.ToCoreBlock(block) - Expect(err).To(Equal(TransActionReceiptError{})) + Expect(err).To(MatchError(fakes.FakeError)) }) }) diff --git a/pkg/geth/converters/rpc/transaction_converter.go b/pkg/geth/converters/rpc/transaction_converter.go index 3bc0988e..c1dda565 100644 --- a/pkg/geth/converters/rpc/transaction_converter.go +++ b/pkg/geth/converters/rpc/transaction_converter.go @@ -14,16 +14,11 @@ import ( vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common" ) -type Client interface { - TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) -} - type RpcTransactionConverter struct { - client Client + client core.EthClient } -func NewRpcTransactionConverter(client Client) *RpcTransactionConverter { +func NewRpcTransactionConverter(client core.EthClient) *RpcTransactionConverter { return &RpcTransactionConverter{client: client} } @@ -42,7 +37,7 @@ func (rtc *RpcTransactionConverter) ConvertTransactionsToCore(gethBlock *types.B return err } coreTransaction := transToCoreTrans(transaction, &from) - coreTransaction, err = appendReceiptToTransaction(rtc.client, coreTransaction) + coreTransaction, err = rtc.appendReceiptToTransaction(coreTransaction) if err != nil { log.Println("receipt: ", err) return err @@ -58,8 +53,8 @@ func (rtc *RpcTransactionConverter) ConvertTransactionsToCore(gethBlock *types.B return coreTransactions, nil } -func appendReceiptToTransaction(client Client, transaction core.Transaction) (core.Transaction, error) { - gethReceipt, err := client.TransactionReceipt(context.Background(), common.HexToHash(transaction.Hash)) +func (rtc *RpcTransactionConverter) appendReceiptToTransaction(transaction core.Transaction) (core.Transaction, error) { + gethReceipt, err := rtc.client.TransactionReceipt(context.Background(), common.HexToHash(transaction.Hash)) if err != nil { return transaction, err } diff --git a/pkg/geth/node/node.go b/pkg/geth/node/node.go index daa20e76..33459e8f 100644 --- a/pkg/geth/node/node.go +++ b/pkg/geth/node/node.go @@ -7,69 +7,38 @@ import ( "regexp" - "strings" - "log" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/p2p" "github.com/vulcanize/vulcanizedb/pkg/core" + "strings" ) -type PropertiesReader interface { +type IPropertiesReader interface { NodeInfo() (id string, name string) NetworkId() float64 GenesisBlock() string } -type ClientWrapper struct { - ContextCaller - IPCPath string -} - -type ContextCaller interface { - CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error - SupportedModules() (map[string]string, error) +type PropertiesReader struct { + client core.RpcClient } type ParityClient struct { - ClientWrapper + PropertiesReader } type GethClient struct { - ClientWrapper + PropertiesReader } type InfuraClient struct { - ClientWrapper + PropertiesReader } -func (clientWrapper ClientWrapper) NodeType() core.NodeType { - if strings.Contains(clientWrapper.IPCPath, "infura") { - return core.INFURA - } - modules, _ := clientWrapper.SupportedModules() - if _, ok := modules["admin"]; ok { - return core.GETH - } - return core.PARITY -} - -func makePropertiesReader(wrapper ClientWrapper) PropertiesReader { - switch wrapper.NodeType() { - case core.GETH: - return GethClient{ClientWrapper: wrapper} - case core.PARITY: - return ParityClient{ClientWrapper: wrapper} - case core.INFURA: - return InfuraClient{ClientWrapper: wrapper} - default: - return wrapper - } -} - -func MakeNode(wrapper ClientWrapper) core.Node { - pr := makePropertiesReader(wrapper) +func MakeNode(rpcClient core.RpcClient) core.Node { + pr := makePropertiesReader(rpcClient) id, name := pr.NodeInfo() return core.Node{ GenesisBlock: pr.GenesisBlock(), @@ -79,9 +48,33 @@ func MakeNode(wrapper ClientWrapper) core.Node { } } -func (client ClientWrapper) NetworkId() float64 { +func makePropertiesReader(client core.RpcClient) IPropertiesReader { + switch getNodeType(client) { + case core.GETH: + return GethClient{PropertiesReader: PropertiesReader{client: client}} + case core.PARITY: + return ParityClient{PropertiesReader: PropertiesReader{client: client}} + case core.INFURA: + return InfuraClient{PropertiesReader: PropertiesReader{client: client}} + default: + return PropertiesReader{client: client} + } +} + +func getNodeType(client core.RpcClient) core.NodeType { + if strings.Contains(client.IpcPath(), "infura") { + return core.INFURA + } + modules, _ := client.SupportedModules() + if _, ok := modules["admin"]; ok { + return core.GETH + } + return core.PARITY +} + +func (reader PropertiesReader) NetworkId() float64 { var version string - err := client.CallContext(context.Background(), &version, "net_version") + err := reader.client.CallContext(context.Background(), &version, "net_version") if err != nil { log.Println(err) } @@ -89,17 +82,17 @@ func (client ClientWrapper) NetworkId() float64 { return networkId } -func (client ClientWrapper) GenesisBlock() string { +func (reader PropertiesReader) GenesisBlock() string { var header *types.Header blockZero := "0x0" includeTransactions := false - client.CallContext(context.Background(), &header, "eth_getBlockByNumber", blockZero, includeTransactions) + reader.client.CallContext(context.Background(), &header, "eth_getBlockByNumber", blockZero, includeTransactions) return header.Hash().Hex() } -func (client ClientWrapper) NodeInfo() (string, string) { +func (reader PropertiesReader) NodeInfo() (string, string) { var info p2p.NodeInfo - client.CallContext(context.Background(), &info, "admin_nodeInfo") + reader.client.CallContext(context.Background(), &info, "admin_nodeInfo") return info.ID, info.Name } @@ -115,14 +108,14 @@ func (client InfuraClient) NodeInfo() (string, string) { func (client ParityClient) parityNodeInfo() string { var nodeInfo core.ParityNodeInfo - client.CallContext(context.Background(), &nodeInfo, "parity_versionInfo") + client.client.CallContext(context.Background(), &nodeInfo, "parity_versionInfo") return nodeInfo.String() } func (client ParityClient) parityID() string { var enodeId = regexp.MustCompile(`^enode://(.+)@.+$`) var enodeURL string - client.CallContext(context.Background(), &enodeURL, "parity_enode") + client.client.CallContext(context.Background(), &enodeURL, "parity_enode") enode := enodeId.FindStringSubmatch(enodeURL) if len(enode) < 2 { return "" diff --git a/pkg/geth/node/node_test.go b/pkg/geth/node/node_test.go index 5fe9d593..ec557369 100644 --- a/pkg/geth/node/node_test.go +++ b/pkg/geth/node/node_test.go @@ -3,66 +3,15 @@ package node_test import ( "encoding/json" - "context" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/p2p" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/geth/node" ) -type MockContextCaller struct { - nodeType core.NodeType -} - var EmpytHeaderHash = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" -func (MockContextCaller) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { - switch method { - case "admin_nodeInfo": - if p, ok := result.(*p2p.NodeInfo); ok { - p.ID = "enode://GethNode@172.17.0.1:30303" - p.Name = "Geth/v1.7" - } - case "eth_getBlockByNumber": - if p, ok := result.(*types.Header); ok { - *p = types.Header{} - } - - case "parity_versionInfo": - if p, ok := result.(*core.ParityNodeInfo); ok { - *p = core.ParityNodeInfo{ - Track: "", - ParityVersion: core.ParityVersion{ - Major: 1, - Minor: 2, - Patch: 3, - }, - Hash: "", - } - } - case "parity_enode": - if p, ok := result.(*string); ok { - *p = "enode://ParityNode@172.17.0.1:30303" - } - case "net_version": - if p, ok := result.(*string); ok { - *p = "1234" - } - } - return nil -} - -func (mcc MockContextCaller) SupportedModules() (map[string]string, error) { - result := make(map[string]string) - if mcc.nodeType == core.GETH { - result["admin"] = "ok" - } - return result, nil -} - var _ = Describe("Parity Node Info", func() { It("verifies parity_versionInfo can be unmarshalled into ParityNodeInfo", func() { @@ -99,39 +48,38 @@ var _ = Describe("Parity Node Info", func() { }) It("returns the genesis block for any client", func() { - mcc := MockContextCaller{} - cw := node.ClientWrapper{ContextCaller: mcc} - n := node.MakeNode(cw) + client := fakes.NewMockRpcClient() + n := node.MakeNode(client) Expect(n.GenesisBlock).To(Equal(EmpytHeaderHash)) }) It("returns the network id for any client", func() { - mcc := MockContextCaller{} - cw := node.ClientWrapper{ContextCaller: mcc} - n := node.MakeNode(cw) + client := fakes.NewMockRpcClient() + n := node.MakeNode(client) Expect(n.NetworkID).To(Equal(float64(1234))) }) It("returns parity ID and client name for parity node", func() { - mcc := MockContextCaller{core.PARITY} - cw := node.ClientWrapper{ContextCaller: mcc} - n := node.MakeNode(cw) + client := fakes.NewMockRpcClient() + client.SetNodeType(core.PARITY) + n := node.MakeNode(client) Expect(n.ID).To(Equal("ParityNode")) Expect(n.ClientName).To(Equal("Parity/v1.2.3/")) }) It("returns geth ID and client name for geth node", func() { - mcc := MockContextCaller{core.GETH} - cw := node.ClientWrapper{ContextCaller: mcc} - n := node.MakeNode(cw) + client := fakes.NewMockRpcClient() + client.SetNodeType(core.GETH) + n := node.MakeNode(client) Expect(n.ID).To(Equal("enode://GethNode@172.17.0.1:30303")) Expect(n.ClientName).To(Equal("Geth/v1.7")) }) It("returns infura ID and client name for infura node", func() { - mcc := MockContextCaller{core.INFURA} - cw := node.ClientWrapper{ContextCaller: mcc, IPCPath: "https://mainnet.infura.io/123"} - n := node.MakeNode(cw) + client := fakes.NewMockRpcClient() + client.SetNodeType(core.INFURA) + client.SetIpcPath("infura/path") + n := node.MakeNode(client) Expect(n.ID).To(Equal("infura")) Expect(n.ClientName).To(Equal("infura")) }) diff --git a/pkg/history/block_validator.go b/pkg/history/block_validator.go index 0166f2e2..4f98cbca 100644 --- a/pkg/history/block_validator.go +++ b/pkg/history/block_validator.go @@ -6,12 +6,12 @@ import ( ) type BlockValidator struct { - blockchain core.Blockchain + blockchain core.BlockChain blockRepository datastore.BlockRepository windowSize int } -func NewBlockValidator(blockchain core.Blockchain, blockRepository datastore.BlockRepository, windowSize int) *BlockValidator { +func NewBlockValidator(blockchain core.BlockChain, blockRepository datastore.BlockRepository, windowSize int) *BlockValidator { return &BlockValidator{ blockchain: blockchain, blockRepository: blockRepository, diff --git a/pkg/history/block_validator_test.go b/pkg/history/block_validator_test.go index ef271b0f..e05e6501 100644 --- a/pkg/history/block_validator_test.go +++ b/pkg/history/block_validator_test.go @@ -4,39 +4,29 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/inmemory" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" + "math/big" ) var _ = Describe("Blocks validator", func() { It("calls create or update for all blocks within the window", func() { - blockchain := fakes.NewMockBlockChainWithBlocks([]core.Block{ - {Number: 4}, - {Number: 5}, - {Number: 6}, - {Number: 7}, - }) - inMemoryDB := inmemory.NewInMemory() - blocksRepository := &inmemory.BlockRepository{InMemory: inMemoryDB} - validator := history.NewBlockValidator(blockchain, blocksRepository, 2) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(7)) + blocksRepository := fakes.NewMockBlockRepository() + validator := history.NewBlockValidator(blockChain, blocksRepository, 2) window := validator.ValidateBlocks() Expect(window).To(Equal(history.ValidationWindow{LowerBound: 5, UpperBound: 7})) - Expect(blocksRepository.BlockCount()).To(Equal(3)) - Expect(blocksRepository.CreateOrUpdateBlockCallCount).To(Equal(3)) + blocksRepository.AssertCreateOrUpdateBlockCallCountEquals(3) }) It("returns the number of largest block", func() { - blockchain := fakes.NewMockBlockChainWithBlocks([]core.Block{ - {Number: 1}, - {Number: 2}, - {Number: 3}, - }) - maxBlockNumber := blockchain.LastBlock() + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(3)) + maxBlockNumber := blockChain.LastBlock() Expect(maxBlockNumber.Int64()).To(Equal(int64(3))) }) diff --git a/pkg/history/header_validator.go b/pkg/history/header_validator.go index d2b549d9..b733aaee 100644 --- a/pkg/history/header_validator.go +++ b/pkg/history/header_validator.go @@ -6,12 +6,12 @@ import ( ) type HeaderValidator struct { - blockChain core.Blockchain + blockChain core.BlockChain headerRepository datastore.HeaderRepository windowSize int } -func NewHeaderValidator(blockChain core.Blockchain, repository datastore.HeaderRepository, windowSize int) HeaderValidator { +func NewHeaderValidator(blockChain core.BlockChain, repository datastore.HeaderRepository, windowSize int) HeaderValidator { return HeaderValidator{ blockChain: blockChain, headerRepository: repository, diff --git a/pkg/history/header_validator_test.go b/pkg/history/header_validator_test.go index 60cae147..379f6739 100644 --- a/pkg/history/header_validator_test.go +++ b/pkg/history/header_validator_test.go @@ -1,39 +1,22 @@ package history_test import ( - "github.com/ethereum/go-ethereum/common" . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/inmemory" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" + "math/big" ) var _ = Describe("Header validator", func() { - It("replaces headers in the validation window that have changed", func() { - blockNumber := int64(10) - oldHash := common.HexToHash("0x0987654321").Hex() - oldHeader := core.Header{ - BlockNumber: blockNumber, - Hash: oldHash, - } - inMemory := inmemory.NewInMemory() - headerRepository := inmemory.NewHeaderRepository(inMemory) - headerRepository.CreateOrUpdateHeader(oldHeader) - newHash := common.HexToHash("0x123456789").Hex() - newHeader := core.Header{ - BlockNumber: blockNumber, - Hash: newHash, - } - headers := []core.Header{newHeader} - blockChain := fakes.NewMockBlockChainWithHeaders(headers) - validator := history.NewHeaderValidator(blockChain, headerRepository, 1) + It("attempts to create every header in the validation window", func() { + headerRepository := fakes.NewMockHeaderRepository() + headerRepository.SetMissingBlockNumbers([]int64{}) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(3)) + validator := history.NewHeaderValidator(blockChain, headerRepository, 2) validator.ValidateHeaders() - dbHeader, _ := headerRepository.GetHeader(blockNumber) - Expect(dbHeader.Hash).NotTo(Equal(oldHash)) - Expect(dbHeader.Hash).To(Equal(newHash)) + headerRepository.AssertCreateOrUpdateHeaderCallCountAndPassedBlockNumbers(3, []int64{1, 2, 3}) }) }) diff --git a/pkg/history/populate_blocks.go b/pkg/history/populate_blocks.go index 3823a745..364f1150 100644 --- a/pkg/history/populate_blocks.go +++ b/pkg/history/populate_blocks.go @@ -7,7 +7,7 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/datastore" ) -func PopulateMissingBlocks(blockchain core.Blockchain, blockRepository datastore.BlockRepository, startingBlockNumber int64) int { +func PopulateMissingBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, startingBlockNumber int64) int { lastBlock := blockchain.LastBlock().Int64() blockRange := blockRepository.MissingBlockNumbers(startingBlockNumber, lastBlock, blockchain.Node().ID) log.SetPrefix("") @@ -16,7 +16,7 @@ func PopulateMissingBlocks(blockchain core.Blockchain, blockRepository datastore return len(blockRange) } -func RetrieveAndUpdateBlocks(blockchain core.Blockchain, blockRepository datastore.BlockRepository, blockNumbers []int64) int { +func RetrieveAndUpdateBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, blockNumbers []int64) int { for _, blockNumber := range blockNumbers { block, err := blockchain.GetBlockByNumber(blockNumber) if err != nil { diff --git a/pkg/history/populate_blocks_test.go b/pkg/history/populate_blocks_test.go index ad464188..e80687a3 100644 --- a/pkg/history/populate_blocks_test.go +++ b/pkg/history/populate_blocks_test.go @@ -1,35 +1,26 @@ package history_test import ( - "errors" - . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/inmemory" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" + "math/big" ) var _ = Describe("Populating blocks", func() { - var inMemory *inmemory.InMemory - var blockRepository *inmemory.BlockRepository + var blockRepository *fakes.MockBlockRepository BeforeEach(func() { - inMemory = inmemory.NewInMemory() - blockRepository = &inmemory.BlockRepository{InMemory: inMemory} + blockRepository = fakes.NewMockBlockRepository() }) It("fills in the only missing block (BlockNumber 1)", func() { - blocks := []core.Block{ - {Number: 1}, - {Number: 2}, - } - blockchain := fakes.NewMockBlockChainWithBlocks(blocks) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(2)) + blockRepository.SetMissingBlockNumbersReturnArray([]int64{2}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 2}) - - blocksAdded := history.PopulateMissingBlocks(blockchain, blockRepository, 1) + blocksAdded := history.PopulateMissingBlocks(blockChain, blockRepository, 1) _, err := blockRepository.GetBlock(1) Expect(blocksAdded).To(Equal(1)) @@ -37,77 +28,41 @@ var _ = Describe("Populating blocks", func() { }) It("fills in the three missing blocks (Numbers: 5,8,10)", func() { - blockchain := fakes.NewMockBlockChainWithBlocks([]core.Block{ - {Number: 4}, - {Number: 5}, - {Number: 6}, - {Number: 7}, - {Number: 8}, - {Number: 9}, - {Number: 10}, - {Number: 11}, - {Number: 12}, - {Number: 13}, - }) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 1}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 2}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 3}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 7}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 9}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 11}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 12}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 13}) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(13)) + blockRepository.SetMissingBlockNumbersReturnArray([]int64{5, 8, 10}) - blocksAdded := history.PopulateMissingBlocks(blockchain, blockRepository, 5) + blocksAdded := history.PopulateMissingBlocks(blockChain, blockRepository, 5) Expect(blocksAdded).To(Equal(3)) - Expect(blockRepository.BlockCount()).To(Equal(12)) - _, err := blockRepository.GetBlock(4) - Expect(err).To(HaveOccurred()) - _, err = blockRepository.GetBlock(5) - Expect(err).ToNot(HaveOccurred()) - _, err = blockRepository.GetBlock(8) - Expect(err).ToNot(HaveOccurred()) - _, err = blockRepository.GetBlock(10) - Expect(err).ToNot(HaveOccurred()) - _, err = blockRepository.GetBlock(14) - Expect(err).To(HaveOccurred()) + blockRepository.AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(3, []int64{5, 8, 10}) }) It("returns the number of blocks created", func() { - blockchain := fakes.NewMockBlockChainWithBlocks([]core.Block{ - {Number: 4}, - {Number: 5}, - {Number: 6}, - }) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 3}) - blockRepository.CreateOrUpdateBlock(core.Block{Number: 6}) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(6)) + blockRepository.SetMissingBlockNumbersReturnArray([]int64{4, 5}) - numberOfBlocksCreated := history.PopulateMissingBlocks(blockchain, blockRepository, 3) + numberOfBlocksCreated := history.PopulateMissingBlocks(blockChain, blockRepository, 3) Expect(numberOfBlocksCreated).To(Equal(2)) }) It("updates the repository with a range of blocks w/in the range ", func() { - blockchain := fakes.NewMockBlockChainWithBlocks([]core.Block{ - {Number: 1}, - {Number: 2}, - {Number: 3}, - {Number: 4}, - {Number: 5}, - }) + blockChain := fakes.NewMockBlockChain() - history.RetrieveAndUpdateBlocks(blockchain, blockRepository, history.MakeRange(2, 5)) - Expect(blockRepository.BlockCount()).To(Equal(4)) - Expect(blockRepository.CreateOrUpdateBlockCallCount).To(Equal(4)) + history.RetrieveAndUpdateBlocks(blockChain, blockRepository, history.MakeRange(2, 5)) + + blockRepository.AssertCreateOrUpdateBlocksCallCountAndBlockNumbersEquals(4, []int64{2, 3, 4, 5}) }) It("does not call repository create block when there is an error", func() { - blockchain := fakes.NewMockBlockChain(errors.New("error getting block")) + blockChain := fakes.NewMockBlockChain() + blockChain.SetGetBlockByNumberErr(fakes.FakeError) blocks := history.MakeRange(1, 10) - history.RetrieveAndUpdateBlocks(blockchain, blockRepository, blocks) - Expect(blockRepository.BlockCount()).To(Equal(0)) - Expect(blockRepository.CreateOrUpdateBlockCallCount).To(Equal(0)) + + history.RetrieveAndUpdateBlocks(blockChain, blockRepository, blocks) + + blockRepository.AssertCreateOrUpdateBlockCallCountEquals(0) }) }) diff --git a/pkg/history/populate_headers.go b/pkg/history/populate_headers.go index 140e81b1..1fc1a80d 100644 --- a/pkg/history/populate_headers.go +++ b/pkg/history/populate_headers.go @@ -6,7 +6,7 @@ import ( "log" ) -func PopulateMissingHeaders(blockchain core.Blockchain, headerRepository datastore.HeaderRepository, startingBlockNumber int64) int { +func PopulateMissingHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, startingBlockNumber int64) int { lastBlock := blockchain.LastBlock().Int64() blockRange := headerRepository.MissingBlockNumbers(startingBlockNumber, lastBlock, blockchain.Node().ID) log.SetPrefix("") @@ -15,7 +15,7 @@ func PopulateMissingHeaders(blockchain core.Blockchain, headerRepository datasto return len(blockRange) } -func RetrieveAndUpdateHeaders(blockchain core.Blockchain, headerRepository datastore.HeaderRepository, blockNumbers []int64) int { +func RetrieveAndUpdateHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, blockNumbers []int64) int { for _, blockNumber := range blockNumbers { header, err := blockchain.GetHeaderByNumber(blockNumber) if err != nil { diff --git a/pkg/history/populate_headers_test.go b/pkg/history/populate_headers_test.go index bb9d41e0..5d3bf8b5 100644 --- a/pkg/history/populate_headers_test.go +++ b/pkg/history/populate_headers_test.go @@ -1,33 +1,29 @@ package history_test import ( + "math/big" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/core" - "github.com/vulcanize/vulcanizedb/pkg/datastore/inmemory" + "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" ) var _ = Describe("Populating headers", func() { - var inMemory *inmemory.InMemory - var headerRepository *inmemory.HeaderRepository + var headerRepository *fakes.MockHeaderRepository BeforeEach(func() { - inMemory = inmemory.NewInMemory() - headerRepository = inmemory.NewHeaderRepository(inMemory) + headerRepository = fakes.NewMockHeaderRepository() }) Describe("When 1 missing header", func() { It("returns number of headers added", func() { - headers := []core.Header{ - {BlockNumber: 1}, - {BlockNumber: 2}, - } - blockChain := fakes.NewMockBlockChainWithHeaders(headers) - headerRepository.CreateOrUpdateHeader(core.Header{BlockNumber: 2}) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(2)) + headerRepository.SetMissingBlockNumbers([]int64{2}) headersAdded := history.PopulateMissingHeaders(blockChain, headerRepository, 1) @@ -36,17 +32,12 @@ var _ = Describe("Populating headers", func() { }) It("adds missing headers to the db", func() { - headers := []core.Header{ - {BlockNumber: 1}, - {BlockNumber: 2}, - } - blockChain := fakes.NewMockBlockChainWithHeaders(headers) - dbHeader, _ := headerRepository.GetHeader(1) - Expect(dbHeader.BlockNumber).To(BeZero()) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(2)) + headerRepository.SetMissingBlockNumbers([]int64{2}) history.PopulateMissingHeaders(blockChain, headerRepository, 1) - dbHeader, _ = headerRepository.GetHeader(1) - Expect(dbHeader.BlockNumber).To(Equal(int64(1))) + headerRepository.AssertCreateOrUpdateHeaderCallCountAndPassedBlockNumbers(1, []int64{2}) }) }) diff --git a/pkg/history/validation_window.go b/pkg/history/validation_window.go index ee59a6c6..e10253c3 100644 --- a/pkg/history/validation_window.go +++ b/pkg/history/validation_window.go @@ -22,7 +22,7 @@ func (window ValidationWindow) Size() int { return int(window.UpperBound - window.LowerBound) } -func MakeValidationWindow(blockchain core.Blockchain, windowSize int) ValidationWindow { +func MakeValidationWindow(blockchain core.BlockChain, windowSize int) ValidationWindow { upperBound := blockchain.LastBlock().Int64() lowerBound := upperBound - int64(windowSize) return ValidationWindow{lowerBound, upperBound} diff --git a/pkg/history/validation_window_test.go b/pkg/history/validation_window_test.go index 5043d352..354af33e 100644 --- a/pkg/history/validation_window_test.go +++ b/pkg/history/validation_window_test.go @@ -6,22 +6,17 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/history" + "math/big" ) -var _ = Describe("", func() { +var _ = Describe("Validation window", func() { It("creates a ValidationWindow equal to (HEAD-windowSize, HEAD)", func() { - blockchain := fakes.NewMockBlockChainWithBlocks([]core.Block{ - {Number: 1}, - {Number: 2}, - {Number: 3}, - {Number: 4}, - {Number: 5}, - }) + blockChain := fakes.NewMockBlockChain() + blockChain.SetLastBlock(big.NewInt(5)) - validationWindow := history.MakeValidationWindow(blockchain, 2) + validationWindow := history.MakeValidationWindow(blockChain, 2) Expect(validationWindow.LowerBound).To(Equal(int64(3))) Expect(validationWindow.UpperBound).To(Equal(int64(5)))