From 9231d403690c0a60fc55bd17fb52b9915d4b1147 Mon Sep 17 00:00:00 2001 From: Rob Mulholand Date: Thu, 26 Jul 2018 17:01:24 -0500 Subject: [PATCH] Extract price feed contract addresses to config --- README.md | 16 +++++-- cmd/lightSync.go | 46 +++++++++++-------- cmd/root.go | 12 +++++ cmd/syncPriceFeeds.go | 40 ++++------------ environments/infura.toml | 3 ++ environments/private.toml | 5 +- environments/public.toml.example | 3 ++ pkg/fakes/mock_blockchain.go | 18 +------- pkg/transformers/price_feeds/constants.go | 3 -- pkg/transformers/price_feeds/pep/fetcher.go | 10 ++-- .../price_feeds/pep/fetcher_test.go | 13 +++--- .../price_feeds/pep/transformer.go | 4 +- .../price_feeds/pep/transformer_test.go | 4 +- pkg/transformers/price_feeds/pip/fetcher.go | 12 +++-- .../price_feeds/pip/fetcher_test.go | 11 +++-- .../price_feeds/pip/transformer.go | 4 +- .../price_feeds/pip/transformer_test.go | 4 +- pkg/transformers/price_feeds/rep/fetcher.go | 23 +++++++--- .../price_feeds/rep/fetcher_test.go | 30 ++++++++---- .../price_feeds/rep/repository_test.go | 1 + .../price_feeds/rep/transformer.go | 4 +- .../price_feeds/rep/transformer_test.go | 9 ++-- test_config/test_config.go | 1 + 23 files changed, 152 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 3b7cd54a..a60426d3 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ Vulcanize DB is a set of tools that make it easier for developers to write appli ## Configuration - To use a local Ethereum node, copy `environments/public.toml.example` to - `environments/public.toml` and update the `ipcPath` and `levelDbPath`. + `environments/public.toml` and update the `ipcPath`, `levelDbPath`, + `pipContractAddress`, `pepContractAddress`, and `repContractAddress`. - `ipcPath` should match the local node's IPC filepath: - when using geth: - The IPC file is called `geth.ipc`. @@ -51,7 +52,10 @@ Vulcanize DB is a set of tools that make it easier for developers to write appli - Linux: `$HOME/.ethereum/geth/chaindata` - `levelDbPath` is irrelevant (and `coldImport` is currently unavailable) if only running parity. -- See `environments/infura.toml` to configure commands to run against infura, if a local node is unavailable. + - `pepContractAddress`, `pipContractAddress`, and `repContractAddress` should match that medianizer + addresses for each pair on the chain you're tracking. See https://makerdao.com/feeds/ + +- See `environments/infura.toml` to configure commands to run against infura, if a local node is unavailable - Copy `environments/local.toml.example` to `environments/local.toml` to configure commands to run against a local node such as [Ganache](https://truffleframework.com/ganache) or [ganache-cli](https://github.com/trufflesuite/ganache-clihttps://github.com/trufflesuite/ganache-cli). ## Start syncing with postgres @@ -75,7 +79,7 @@ Sync VulcanizeDB from the LevelDB underlying a Geth node. Syncs VulcanizeDB with the configured Ethereum node, populating only block headers. This command is useful when you want a minimal baseline from which to track targeted data on the blockchain (e.g. individual smart contract storage values). 1. Start Ethereum node -2. In a separate terminal start VulcanizeDB: +1. In a separate terminal start VulcanizeDB: - `./vulcanizedb lightSync --config --starting-block-number ` ## Backfill Auction event logs from light sync @@ -87,6 +91,12 @@ _Since auction contracts have not yet been deployed, this command will need to b 1. Start Ethereum node 1. In a separate terminal run the backfill command: - `./vulcanizedb backfillAuctionLogs --config ` + +## Sync in light mode with MakerDAO price feeds +Sync VulcanizeDB with the configured Ethereum node, populating block headers as well as price feeds for MKR/USD, ETH/USD, and REP/USD. +1. Start Ethereum node +1. In a separate terminal window start VulcanizeDB + - `./vulcanizedb syncPriceFeeds --config --starting-block-number ` ## Start full environment in docker by single command diff --git a/cmd/lightSync.go b/cmd/lightSync.go index dbdcf25f..0c91b57b 100644 --- a/cmd/lightSync.go +++ b/cmd/lightSync.go @@ -76,26 +76,10 @@ func backFillAllHeaders(blockchain core.BlockChain, headerRepository datastore.H func lightSync() { ticker := time.NewTicker(pollingInterval) defer ticker.Stop() - rawRpcClient, err := rpc.Dial(ipc) - if err != nil { - log.Fatal(err) - } - 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() - if lastBlock == 0 { - log.Fatal("geth initial: state sync not finished") - } - if startingBlockNumber > lastBlock { - log.Fatal("starting block number > current block number") - } - + blockChain := getBlockChain() + validateArgs(blockChain) db := utils.LoadPostgres(databaseConfig, blockChain.Node()) + headerRepository := repositories.NewHeaderRepository(&db) validator := history.NewHeaderValidator(blockChain, headerRepository, validationWindow, []transformers.Transformer{}) missingBlocksPopulated := make(chan int) @@ -111,3 +95,27 @@ func lightSync() { } } } + +func validateArgs(blockChain *geth.BlockChain) { + lastBlock := blockChain.LastBlock().Int64() + if lastBlock == 0 { + log.Fatal("geth initial: state sync not finished") + } + if startingBlockNumber > lastBlock { + log.Fatal("starting block number > current block number") + } +} + +func getBlockChain() *geth.BlockChain { + rawRpcClient, err := rpc.Dial(ipc) + if err != nil { + log.Fatal(err) + } + 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) + return blockChain +} diff --git a/cmd/root.go b/cmd/root.go index c0336edc..ea51e448 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -29,6 +29,9 @@ var ( databaseConfig config.Database ipc string levelDbPath string + pepContractAddress string + pipContractAddress string + repContractAddress string startingBlockNumber int64 syncAll bool endingBlockNumber int64 @@ -49,6 +52,9 @@ func Execute() { func database(cmd *cobra.Command, args []string) { ipc = viper.GetString("client.ipcpath") levelDbPath = viper.GetString("client.leveldbpath") + pepContractAddress = viper.GetString("client.pepcontractaddress") + pipContractAddress = viper.GetString("client.pipcontractaddress") + repContractAddress = viper.GetString("client.repcontractaddress") databaseConfig = config.Database{ Name: viper.GetString("database.name"), Hostname: viper.GetString("database.hostname"), @@ -70,6 +76,9 @@ func init() { rootCmd.PersistentFlags().String("database-password", "", "database password") rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file") rootCmd.PersistentFlags().String("client-levelDbPath", "", "location of levelDb chaindata") + rootCmd.PersistentFlags().String("client-pepContractAddress", "", "mkr/usd price feed contract address") + rootCmd.PersistentFlags().String("client-pipContractAddress", "", "eth/usd price feed contract address") + rootCmd.PersistentFlags().String("client-repContractAddress", "", "rep/usd price feed contract address") viper.BindPFlag("database.name", rootCmd.PersistentFlags().Lookup("database-name")) viper.BindPFlag("database.port", rootCmd.PersistentFlags().Lookup("database-port")) @@ -78,6 +87,9 @@ func init() { viper.BindPFlag("database.password", rootCmd.PersistentFlags().Lookup("database-password")) viper.BindPFlag("client.ipcPath", rootCmd.PersistentFlags().Lookup("client-ipcPath")) viper.BindPFlag("client.levelDbPath", rootCmd.PersistentFlags().Lookup("client-levelDbPath")) + viper.BindPFlag("client.pepContractAddress", rootCmd.PersistentFlags().Lookup("client-pepContractAddress")) + viper.BindPFlag("client.pipContractAddress", rootCmd.PersistentFlags().Lookup("client-pipContractAddress")) + viper.BindPFlag("client.repContractAddress", rootCmd.PersistentFlags().Lookup("client-repContractAddress")) } func initConfig() { diff --git a/cmd/syncPriceFeeds.go b/cmd/syncPriceFeeds.go index ae16a262..32edaf3f 100644 --- a/cmd/syncPriceFeeds.go +++ b/cmd/syncPriceFeeds.go @@ -1,4 +1,4 @@ -// Copyright © 2018 NAME HERE +// Copyright © 2018 Vulcanize // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,17 +19,11 @@ import ( "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" - 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/pkg/transformers" "github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/pep" @@ -68,33 +62,17 @@ func backFillPriceFeeds(blockchain core.BlockChain, headerRepository datastore.H func syncPriceFeeds() { ticker := time.NewTicker(pollingInterval) defer ticker.Stop() - rawRpcClient, err := rpc.Dial(ipc) - if err != nil { - log.Fatal(err) - } - 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() - if lastBlock == 0 { - log.Fatal("geth initial: state sync not finished") - } - if startingBlockNumber > lastBlock { - log.Fatal("starting block number > current block number") - } - + blockChain := getBlockChain() + validateArgs(blockChain) db := utils.LoadPostgres(databaseConfig, blockChain.Node()) + + transformers := []transformers.Transformer{ + pep.NewPepTransformer(blockChain, &db, pepContractAddress), + pip.NewPipTransformer(blockChain, &db, pipContractAddress), + rep.NewRepTransformer(blockChain, &db, repContractAddress), + } headerRepository := repositories.NewHeaderRepository(&db) missingBlocksPopulated := make(chan int) - transformers := []transformers.Transformer{ - pep.NewPepTransformer(blockChain, &db), - pip.NewPipTransformer(blockChain, &db), - rep.NewRepTransformer(blockChain, &db), - } validator := history.NewHeaderValidator(blockChain, headerRepository, validationWindow, transformers) go backFillPriceFeeds(blockChain, headerRepository, missingBlocksPopulated, startingBlockNumber, transformers) diff --git a/environments/infura.toml b/environments/infura.toml index e1539f3d..30db3365 100644 --- a/environments/infura.toml +++ b/environments/infura.toml @@ -5,3 +5,6 @@ port = 5432 [client] ipcPath = "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" +pepContractAddress = "0x99041F808D598B782D5a3e498681C2452A31da08" +pipContractAddress = "0x729D19f657BD0614b4985Cf1D82531c67569197B" +repContractAddress = "0xF5f94b7F9De14D43112e713835BCef2d55b76c1C" diff --git a/environments/private.toml b/environments/private.toml index 30382733..2193e44f 100644 --- a/environments/private.toml +++ b/environments/private.toml @@ -4,4 +4,7 @@ hostname = "localhost" port = 5432 [client] -ipcPath = "http://127.0.0.1:7545" \ No newline at end of file +ipcPath = "http://127.0.0.1:7545" +pepContractAddress = "0x99041F808D598B782D5a3e498681C2452A31da08" +pipContractAddress = "0x729D19f657BD0614b4985Cf1D82531c67569197B" +repContractAddress = "0xF5f94b7F9De14D43112e713835BCef2d55b76c1C" diff --git a/environments/public.toml.example b/environments/public.toml.example index ac9dbf85..c92e03a9 100644 --- a/environments/public.toml.example +++ b/environments/public.toml.example @@ -6,3 +6,6 @@ port = 5432 [client] ipcPath = levelDbPath = +pepContractAddress = +pipContractAddress = +repContractAddress = \ No newline at end of file diff --git a/pkg/fakes/mock_blockchain.go b/pkg/fakes/mock_blockchain.go index 4869bdae..2ce7e3f0 100644 --- a/pkg/fakes/mock_blockchain.go +++ b/pkg/fakes/mock_blockchain.go @@ -18,11 +18,6 @@ type MockBlockChain struct { fetchContractDataPassedMethodArg interface{} fetchContractDataPassedResult interface{} fetchContractDataPassedBlockNumber int64 - getLogsPassedContract core.Contract - getLogsPassedStartingBlockNumber *big.Int - getLogsPassedEndingBlockNumber *big.Int - getLogsReturnLogs []core.Log - getLogsReturnErr error getBlockByNumberErr error logQuery ethereum.FilterQuery logQueryErr error @@ -57,14 +52,6 @@ func (chain *MockBlockChain) SetGetEthLogsWithCustomQueryReturnLogs(logs []types chain.logQueryReturnLogs = logs } -func (chain *MockBlockChain) SetGetLogsReturnErr(err error) { - chain.getLogsReturnErr = err -} - -func (chain *MockBlockChain) SetGetLogsReturnLogs(logs []core.Log) { - chain.getLogsReturnLogs = logs -} - func (chain *MockBlockChain) FetchContractData(abiJSON, address, method string, methodArg, result interface{}, blockNumber int64) error { chain.fetchContractDataPassedAbi = abiJSON chain.fetchContractDataPassedAddress = address @@ -89,10 +76,7 @@ func (chain *MockBlockChain) GetHeaderByNumber(blockNumber int64) (core.Header, } func (chain *MockBlockChain) GetLogs(contract core.Contract, startingBlockNumber, endingBlockNumber *big.Int) ([]core.Log, error) { - chain.getLogsPassedContract = contract - chain.getLogsPassedStartingBlockNumber = startingBlockNumber - chain.getLogsPassedEndingBlockNumber = endingBlockNumber - return chain.getLogsReturnLogs, chain.getLogsReturnErr + return []core.Log{}, nil } func (chain *MockBlockChain) CallContract(contractHash string, input []byte, blockNumber *big.Int) ([]byte, error) { diff --git a/pkg/transformers/price_feeds/constants.go b/pkg/transformers/price_feeds/constants.go index 07f4a674..dc7ecd86 100644 --- a/pkg/transformers/price_feeds/constants.go +++ b/pkg/transformers/price_feeds/constants.go @@ -10,12 +10,9 @@ var ( ErrNoMatchingLog = errors.New("no matching log") Ether = big.NewFloat(1e18) PeekMethodName = "peek" - PepAddress = "0x99041F808D598B782D5a3e498681C2452A31da08" PepLogTopic0 = "0x296ba4ca62c6c21c95e828080cb8aec7481b71390585605300a8a76f9e95b527" - PipAddress = "0x729D19f657BD0614b4985Cf1D82531c67569197B" PipLogTopic0 = "0x1817835800000000000000000000000000000000000000000000000000000000" PipMedianizerABI = `[{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"","type":"bytes32"}],"name":"poke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"poke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"compute","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wat","type":"address"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wat","type":"address"}],"name":"unset","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"indexes","outputs":[{"name":"","type":"bytes12"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"next","outputs":[{"name":"","type":"bytes12"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"read","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"peek","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes12"}],"name":"values","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"min_","type":"uint96"}],"name":"setMin","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"void","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"pos","type":"bytes12"},{"name":"wat","type":"address"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"pos","type":"bytes12"}],"name":"unset","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"next_","type":"bytes12"}],"name":"setNext","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"min","outputs":[{"name":"","type":"uint96"}],"payable":false,"type":"function"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"}]` Ray = big.NewFloat(1e27) - RepAddress = "0xF5f94b7F9De14D43112e713835BCef2d55b76c1C" RepLogTopic0 = "0x296ba4ca62c6c21c95e828080cb8aec7481b71390585605300a8a76f9e95b527" ) diff --git a/pkg/transformers/price_feeds/pep/fetcher.go b/pkg/transformers/price_feeds/pep/fetcher.go index 827cb0d3..19b86738 100644 --- a/pkg/transformers/price_feeds/pep/fetcher.go +++ b/pkg/transformers/price_feeds/pep/fetcher.go @@ -16,12 +16,14 @@ type IPepFetcher interface { } type PepFetcher struct { - blockChain core.BlockChain + blockChain core.BlockChain + contractAddress string } -func NewPepFetcher(chain core.BlockChain) PepFetcher { +func NewPepFetcher(chain core.BlockChain, contractAddress string) PepFetcher { return PepFetcher{ - blockChain: chain, + blockChain: chain, + contractAddress: contractAddress, } } @@ -30,7 +32,7 @@ func (fetcher PepFetcher) FetchPepValue(header core.Header) (string, error) { query := ethereum.FilterQuery{ FromBlock: blockNumber, ToBlock: blockNumber, - Addresses: []common.Address{common.HexToAddress(price_feeds.PepAddress)}, + Addresses: []common.Address{common.HexToAddress(fetcher.contractAddress)}, Topics: [][]common.Hash{{common.HexToHash(price_feeds.PepLogTopic0)}}, } logs, err := fetcher.blockChain.GetEthLogsWithCustomQuery(query) diff --git a/pkg/transformers/price_feeds/pep/fetcher_test.go b/pkg/transformers/price_feeds/pep/fetcher_test.go index 209edef0..7342e9e8 100644 --- a/pkg/transformers/price_feeds/pep/fetcher_test.go +++ b/pkg/transformers/price_feeds/pep/fetcher_test.go @@ -18,8 +18,9 @@ var _ = Describe("Pep fetcher", func() { It("gets logs describing updated mkr/usd value", func() { mockBlockChain := fakes.NewMockBlockChain() mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{}}) - fetcher := pep.NewPepFetcher(mockBlockChain) - blockNumber := int64(100) + contractAddress := "pep-contract-address" + fetcher := pep.NewPepFetcher(mockBlockChain, contractAddress) + blockNumber := int64(12345) header := core.Header{ BlockNumber: blockNumber, Hash: "", @@ -32,7 +33,7 @@ var _ = Describe("Pep fetcher", func() { expectedQuery := ethereum.FilterQuery{ FromBlock: big.NewInt(blockNumber), ToBlock: big.NewInt(blockNumber), - Addresses: []common.Address{common.HexToAddress(price_feeds.PepAddress)}, + Addresses: []common.Address{common.HexToAddress(contractAddress)}, Topics: [][]common.Hash{{common.HexToHash(price_feeds.PepLogTopic0)}}, } mockBlockChain.AssertGetEthLogsWithCustomQueryCalledWith(expectedQuery) @@ -42,7 +43,7 @@ var _ = Describe("Pep fetcher", func() { mockBlockChain := fakes.NewMockBlockChain() mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{}}) mockBlockChain.SetGetEthLogsWithCustomQueryErr(fakes.FakeError) - fetcher := pep.NewPepFetcher(mockBlockChain) + fetcher := pep.NewPepFetcher(mockBlockChain, "pep-contract-address") _, err := fetcher.FetchPepValue(core.Header{}) @@ -52,7 +53,7 @@ var _ = Describe("Pep fetcher", func() { It("returns no matching logs error if no logs returned", func() { mockBlockChain := fakes.NewMockBlockChain() - fetcher := pep.NewPepFetcher(mockBlockChain) + fetcher := pep.NewPepFetcher(mockBlockChain, "pep-contract-address") _, err := fetcher.FetchPepValue(core.Header{}) @@ -63,7 +64,7 @@ var _ = Describe("Pep fetcher", func() { It("returns error if more than one matching logs returned", func() { mockBlockChain := fakes.NewMockBlockChain() mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{}, {}}) - fetcher := pep.NewPepFetcher(mockBlockChain) + fetcher := pep.NewPepFetcher(mockBlockChain, "pep-contract-address") _, err := fetcher.FetchPepValue(core.Header{}) diff --git a/pkg/transformers/price_feeds/pep/transformer.go b/pkg/transformers/price_feeds/pep/transformer.go index c108cbca..8f83f4de 100644 --- a/pkg/transformers/price_feeds/pep/transformer.go +++ b/pkg/transformers/price_feeds/pep/transformer.go @@ -11,8 +11,8 @@ type PepTransformer struct { repository IPepRepository } -func NewPepTransformer(chain core.BlockChain, db *postgres.DB) PepTransformer { - fetcher := NewPepFetcher(chain) +func NewPepTransformer(chain core.BlockChain, db *postgres.DB, contractAddress string) PepTransformer { + fetcher := NewPepFetcher(chain, contractAddress) repository := NewPepRepository(db) return PepTransformer{ fetcher: fetcher, diff --git a/pkg/transformers/price_feeds/pep/transformer_test.go b/pkg/transformers/price_feeds/pep/transformer_test.go index ec6d6d9c..746aa0ca 100644 --- a/pkg/transformers/price_feeds/pep/transformer_test.go +++ b/pkg/transformers/price_feeds/pep/transformer_test.go @@ -17,7 +17,7 @@ var _ = Describe("Pep transformer", func() { It("returns nil if no logs found", func() { chain := fakes.NewMockBlockChain() db := test_config.NewTestDB(core.Node{}) - transformer := pep.NewPepTransformer(chain, db) + transformer := pep.NewPepTransformer(chain, db, "pep-contract-address") err := transformer.Execute(core.Header{}, 123) @@ -33,7 +33,7 @@ var _ = Describe("Pep transformer", func() { header := core.Header{BlockNumber: 12345} headerID, err := headerRepository.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) - transformer := pep.NewPepTransformer(chain, db) + transformer := pep.NewPepTransformer(chain, db, "pep-contract-address") err = transformer.Execute(header, headerID) diff --git a/pkg/transformers/price_feeds/pip/fetcher.go b/pkg/transformers/price_feeds/pip/fetcher.go index 849cc147..08c8a321 100644 --- a/pkg/transformers/price_feeds/pip/fetcher.go +++ b/pkg/transformers/price_feeds/pip/fetcher.go @@ -14,12 +14,14 @@ type IPipFetcher interface { } type PipFetcher struct { - blockChain core.BlockChain + blockChain core.BlockChain + contractAddress string } -func NewPipFetcher(chain core.BlockChain) PipFetcher { +func NewPipFetcher(chain core.BlockChain, contractAddress string) PipFetcher { return PipFetcher{ - blockChain: chain, + blockChain: chain, + contractAddress: contractAddress, } } @@ -28,7 +30,7 @@ func (fetcher PipFetcher) FetchPipValue(header core.Header) (string, error) { query := ethereum.FilterQuery{ FromBlock: blockNumber, ToBlock: blockNumber, - Addresses: []common.Address{common.HexToAddress(price_feeds.PipAddress)}, + Addresses: []common.Address{common.HexToAddress(fetcher.contractAddress)}, Topics: [][]common.Hash{{common.HexToHash(price_feeds.PipLogTopic0)}}, } logs, err := fetcher.blockChain.GetEthLogsWithCustomQuery(query) @@ -50,7 +52,7 @@ func (fetcher PipFetcher) getLogValue(logs []types.Log, err error) (string, erro ret0, ret1, } - err = fetcher.blockChain.FetchContractData(price_feeds.PipMedianizerABI, price_feeds.PipAddress, price_feeds.PeekMethodName, nil, r, int64(logs[0].BlockNumber)) + err = fetcher.blockChain.FetchContractData(price_feeds.PipMedianizerABI, fetcher.contractAddress, price_feeds.PeekMethodName, nil, r, int64(logs[0].BlockNumber)) if err != nil { return "", err } diff --git a/pkg/transformers/price_feeds/pip/fetcher_test.go b/pkg/transformers/price_feeds/pip/fetcher_test.go index c5acdc69..e9cdc053 100644 --- a/pkg/transformers/price_feeds/pip/fetcher_test.go +++ b/pkg/transformers/price_feeds/pip/fetcher_test.go @@ -14,7 +14,7 @@ var _ = Describe("Pip fetcher", func() { It("returns error if fetching logs fails", func() { chain := fakes.NewMockBlockChain() chain.SetGetEthLogsWithCustomQueryErr(fakes.FakeError) - fetcher := pip.NewPipFetcher(chain) + fetcher := pip.NewPipFetcher(chain, "pip-contract-address") _, err := fetcher.FetchPipValue(core.Header{}) @@ -24,7 +24,7 @@ var _ = Describe("Pip fetcher", func() { It("returns no matching logs error if no logs returned", func() { chain := fakes.NewMockBlockChain() - fetcher := pip.NewPipFetcher(chain) + fetcher := pip.NewPipFetcher(chain, "pip-contract-address") _, err := fetcher.FetchPipValue(core.Header{}) @@ -37,19 +37,20 @@ var _ = Describe("Pip fetcher", func() { blockNumber := uint64(12345) chain := fakes.NewMockBlockChain() chain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{BlockNumber: blockNumber}}) - fetcher := pip.NewPipFetcher(chain) + contractAddress := "pip-contract-address" + fetcher := pip.NewPipFetcher(chain, contractAddress) _, err := fetcher.FetchPipValue(core.Header{}) Expect(err).NotTo(HaveOccurred()) - chain.AssertFetchContractDataCalledWith(price_feeds.PipMedianizerABI, price_feeds.PipAddress, price_feeds.PeekMethodName, nil, &[]interface{}{[32]byte{}, false}, int64(blockNumber)) + chain.AssertFetchContractDataCalledWith(price_feeds.PipMedianizerABI, contractAddress, price_feeds.PeekMethodName, nil, &[]interface{}{[32]byte{}, false}, int64(blockNumber)) }) It("returns error if contract call fails", func() { chain := fakes.NewMockBlockChain() chain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{BlockNumber: uint64(12345)}}) chain.SetFetchContractDataErr(fakes.FakeError) - fetcher := pip.NewPipFetcher(chain) + fetcher := pip.NewPipFetcher(chain, "pip-contract-address") _, err := fetcher.FetchPipValue(core.Header{}) diff --git a/pkg/transformers/price_feeds/pip/transformer.go b/pkg/transformers/price_feeds/pip/transformer.go index 8b66b4dd..03845e8d 100644 --- a/pkg/transformers/price_feeds/pip/transformer.go +++ b/pkg/transformers/price_feeds/pip/transformer.go @@ -11,8 +11,8 @@ type PipTransformer struct { repository IPipRepository } -func NewPipTransformer(chain core.BlockChain, db *postgres.DB) PipTransformer { - fetcher := NewPipFetcher(chain) +func NewPipTransformer(chain core.BlockChain, db *postgres.DB, contractAddress string) PipTransformer { + fetcher := NewPipFetcher(chain, contractAddress) repository := NewPipRepository(db) return PipTransformer{ fetcher: fetcher, diff --git a/pkg/transformers/price_feeds/pip/transformer_test.go b/pkg/transformers/price_feeds/pip/transformer_test.go index 729de585..be6ef755 100644 --- a/pkg/transformers/price_feeds/pip/transformer_test.go +++ b/pkg/transformers/price_feeds/pip/transformer_test.go @@ -16,7 +16,7 @@ var _ = Describe("Pip transformer", func() { It("returns nil if no logs found", func() { chain := fakes.NewMockBlockChain() db := test_config.NewTestDB(core.Node{}) - transformer := pip.NewPipTransformer(chain, db) + transformer := pip.NewPipTransformer(chain, db, "pip-contract-address") err := transformer.Execute(core.Header{}, 123) @@ -32,7 +32,7 @@ var _ = Describe("Pip transformer", func() { header := core.Header{BlockNumber: 12345} headerID, err := headerRepository.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) - transformer := pip.NewPipTransformer(chain, db) + transformer := pip.NewPipTransformer(chain, db, "pip-contract-address") err = transformer.Execute(header, headerID) diff --git a/pkg/transformers/price_feeds/rep/fetcher.go b/pkg/transformers/price_feeds/rep/fetcher.go index edb9289c..f4f0ce68 100644 --- a/pkg/transformers/price_feeds/rep/fetcher.go +++ b/pkg/transformers/price_feeds/rep/fetcher.go @@ -1,6 +1,9 @@ package rep import ( + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds" "math/big" @@ -11,22 +14,30 @@ type IRepFetcher interface { } type RepFetcher struct { - chain core.BlockChain + chain core.BlockChain + contractAddress string } -func NewRepFetcher(chain core.BlockChain) RepFetcher { +func NewRepFetcher(chain core.BlockChain, contractAddress string) RepFetcher { return RepFetcher{ - chain: chain, + chain: chain, + contractAddress: contractAddress, } } func (fetcher RepFetcher) FetchRepValue(header core.Header) (string, error) { blockNumber := big.NewInt(header.BlockNumber) - logs, err := fetcher.chain.GetLogs(price_feeds.RepAddress, price_feeds.RepLogTopic0, blockNumber, blockNumber) + query := ethereum.FilterQuery{ + FromBlock: blockNumber, + ToBlock: blockNumber, + Addresses: []common.Address{common.HexToAddress(fetcher.contractAddress)}, + Topics: [][]common.Hash{{common.HexToHash(price_feeds.RepLogTopic0)}}, + } + logs, err := fetcher.chain.GetEthLogsWithCustomQuery(query) return fetcher.getLogValue(logs, err) } -func (fetcher RepFetcher) getLogValue(logs []core.Log, err error) (string, error) { +func (fetcher RepFetcher) getLogValue(logs []types.Log, err error) (string, error) { if err != nil { return "", err } @@ -36,5 +47,5 @@ func (fetcher RepFetcher) getLogValue(logs []core.Log, err error) (string, error if len(logs) > 1 { return "", price_feeds.ErrMultipleLogs } - return logs[0].Data, nil + return string(logs[0].Data), nil } diff --git a/pkg/transformers/price_feeds/rep/fetcher_test.go b/pkg/transformers/price_feeds/rep/fetcher_test.go index ba1fac2c..5b9a3796 100644 --- a/pkg/transformers/price_feeds/rep/fetcher_test.go +++ b/pkg/transformers/price_feeds/rep/fetcher_test.go @@ -1,6 +1,9 @@ package rep_test import ( + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/core" @@ -13,10 +16,12 @@ import ( var _ = Describe("Rep fetcher", func() { It("gets logs describing updated rep/usd value", func() { mockBlockChain := fakes.NewMockBlockChain() - mockBlockChain.SetGetLogsReturnLogs([]core.Log{{}}) - fetcher := rep.NewRepFetcher(mockBlockChain) + mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{}}) + contractAddress := "rep-contract-address" + fetcher := rep.NewRepFetcher(mockBlockChain, contractAddress) + blockNumber := int64(100) header := core.Header{ - BlockNumber: 100, + BlockNumber: blockNumber, Hash: "", Raw: nil, } @@ -24,14 +29,19 @@ var _ = Describe("Rep fetcher", func() { _, err := fetcher.FetchRepValue(header) Expect(err).NotTo(HaveOccurred()) - mockBlockChain.AssertGetLogsCalledWith(price_feeds.RepAddress, price_feeds.RepLogTopic0, big.NewInt(header.BlockNumber), big.NewInt(header.BlockNumber)) + expectedQuery := ethereum.FilterQuery{ + FromBlock: big.NewInt(blockNumber), + ToBlock: big.NewInt(blockNumber), + Addresses: []common.Address{common.HexToAddress(contractAddress)}, + Topics: [][]common.Hash{{common.HexToHash(price_feeds.RepLogTopic0)}}, + } + mockBlockChain.AssertGetEthLogsWithCustomQueryCalledWith(expectedQuery) }) It("returns error if getting logs fails", func() { mockBlockChain := fakes.NewMockBlockChain() - mockBlockChain.SetGetLogsReturnLogs([]core.Log{{}}) - mockBlockChain.SetGetLogsReturnErr(fakes.FakeError) - fetcher := rep.NewRepFetcher(mockBlockChain) + mockBlockChain.SetGetEthLogsWithCustomQueryErr(fakes.FakeError) + fetcher := rep.NewRepFetcher(mockBlockChain, "rep-contract-address") _, err := fetcher.FetchRepValue(core.Header{}) @@ -41,7 +51,7 @@ var _ = Describe("Rep fetcher", func() { It("returns no matching logs error if no logs returned", func() { mockBlockChain := fakes.NewMockBlockChain() - fetcher := rep.NewRepFetcher(mockBlockChain) + fetcher := rep.NewRepFetcher(mockBlockChain, "rep-contract-address") _, err := fetcher.FetchRepValue(core.Header{}) @@ -51,8 +61,8 @@ var _ = Describe("Rep fetcher", func() { It("returns error if more than one matching logs returned", func() { mockBlockChain := fakes.NewMockBlockChain() - mockBlockChain.SetGetLogsReturnLogs([]core.Log{{}, {}}) - fetcher := rep.NewRepFetcher(mockBlockChain) + mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{}, {}}) + fetcher := rep.NewRepFetcher(mockBlockChain, "rep-contract-address") _, err := fetcher.FetchRepValue(core.Header{}) diff --git a/pkg/transformers/price_feeds/rep/repository_test.go b/pkg/transformers/price_feeds/rep/repository_test.go index 003df5b7..0ed535d5 100644 --- a/pkg/transformers/price_feeds/rep/repository_test.go +++ b/pkg/transformers/price_feeds/rep/repository_test.go @@ -27,6 +27,7 @@ var _ = Describe("Rep repository", func() { It("creates a rep when matching header exists", func() { db := test_config.NewTestDB(core.Node{}) + test_config.CleanTestDB(db) repository := rep.NewRepRepository(db) header := core.Header{BlockNumber: 12345} headerRepository := repositories.NewHeaderRepository(db) diff --git a/pkg/transformers/price_feeds/rep/transformer.go b/pkg/transformers/price_feeds/rep/transformer.go index 2803855a..fe692c5d 100644 --- a/pkg/transformers/price_feeds/rep/transformer.go +++ b/pkg/transformers/price_feeds/rep/transformer.go @@ -11,8 +11,8 @@ type RepTransformer struct { repository IRepRepository } -func NewRepTransformer(chain core.BlockChain, db *postgres.DB) RepTransformer { - fetcher := NewRepFetcher(chain) +func NewRepTransformer(chain core.BlockChain, db *postgres.DB, contractAddress string) RepTransformer { + fetcher := NewRepFetcher(chain, contractAddress) repository := NewRepRepository(db) return RepTransformer{ fetcher: fetcher, diff --git a/pkg/transformers/price_feeds/rep/transformer_test.go b/pkg/transformers/price_feeds/rep/transformer_test.go index 9194b31b..5bcce1e3 100644 --- a/pkg/transformers/price_feeds/rep/transformer_test.go +++ b/pkg/transformers/price_feeds/rep/transformer_test.go @@ -1,10 +1,10 @@ package rep_test import ( - "github.com/ethereum/go-ethereum/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/ethereum/go-ethereum/core/types" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/pkg/fakes" @@ -17,7 +17,7 @@ var _ = Describe("Rep transformer", func() { It("returns nil if no logs found", func() { chain := fakes.NewMockBlockChain() db := test_config.NewTestDB(core.Node{}) - transformer := rep.NewRepTransformer(chain, db) + transformer := rep.NewRepTransformer(chain, db, "rep-contract-address") err := transformer.Execute(core.Header{}, 123) @@ -26,13 +26,14 @@ var _ = Describe("Rep transformer", func() { It("creates rep row for found log", func() { chain := fakes.NewMockBlockChain() - chain.SetGetLogsReturnLogs([]core.Log{{Data: common.ToHex([]byte{1, 2, 3, 4, 5})}}) + chain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{{Data: []byte{1, 2, 3, 4, 5}}}) db := test_config.NewTestDB(core.Node{}) + test_config.CleanTestDB(db) headerRepository := repositories.NewHeaderRepository(db) header := core.Header{BlockNumber: 12345} headerID, err := headerRepository.CreateOrUpdateHeader(header) Expect(err).NotTo(HaveOccurred()) - transformer := rep.NewRepTransformer(chain, db) + transformer := rep.NewRepTransformer(chain, db, "rep-contract-address") err = transformer.Execute(header, headerID) diff --git a/test_config/test_config.go b/test_config/test_config.go index 845cd00f..2d240572 100644 --- a/test_config/test_config.go +++ b/test_config/test_config.go @@ -79,6 +79,7 @@ func CleanTestDB(db *postgres.DB) { db.MustExec("DELETE FROM logs") db.MustExec("DELETE FROM maker.peps") db.MustExec("DELETE FROM maker.pips") + db.MustExec("DELETE FROM maker.reps") db.MustExec("DELETE FROM receipts") db.MustExec("DELETE FROM transactions") db.MustExec("DELETE FROM watched_contracts")