From a6f606f72fb6d026a2f71218f395c38641f6fea7 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Thu, 10 Sep 2020 17:04:17 -0500 Subject: [PATCH 1/2] load node info from config --- cmd/root.go | 2 +- environments/example.toml | 9 ++ integration_test/header_fetcher_test.go | 4 +- pkg/core/node_info.go | 21 +--- pkg/fakes/mock_rpc_client.go | 12 -- pkg/node/node.go | 161 ++++-------------------- pkg/node/node_test.go | 87 +------------ 7 files changed, 39 insertions(+), 257 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index f331d15b..11c80b62 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -148,7 +148,7 @@ func initConfig() { func getFetcher() *fetcher.Fetcher { rpcClient, ethClient := getClients() - vdbNode := node.MakeNode(rpcClient) + vdbNode := node.MakeNode() return fetcher.NewFetcher(ethClient, rpcClient, vdbNode) } diff --git a/environments/example.toml b/environments/example.toml index f6da5ecd..021327ae 100644 --- a/environments/example.toml +++ b/environments/example.toml @@ -5,3 +5,12 @@ [client] rpcPath = "/geth.ipc" + +[ethereum] + wsPath = "127.0.0.1:8546" # $ETH_WS_PATH + httpPath = "127.0.0.1:8545" # $ETH_HTTP_PATH + nodeID = "arch1" # $ETH_NODE_ID + clientName = "Geth" # $ETH_CLIENT_NAME + genesisBlock = "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" # $ETH_GENESIS_BLOCK + networkID = "1" # $ETH_NETWORK_ID + chainID = "1" # $ETH_CHAIN_ID diff --git a/integration_test/header_fetcher_test.go b/integration_test/header_fetcher_test.go index ab17dfed..a2a549a2 100644 --- a/integration_test/header_fetcher_test.go +++ b/integration_test/header_fetcher_test.go @@ -37,8 +37,8 @@ var _ = Describe("Reading from the Geth blockchain", func() { Expect(err).NotTo(HaveOccurred()) rpcClient := client.NewRPCClient(rawRPCClient, test_config.TestClient.RPCPath) ethClient := ethclient.NewClient(rawRPCClient) - node := node.MakeNode(rpcClient) - fetch = fetcher.NewFetcher(ethClient, rpcClient, node) + n := node.MakeNode() + fetch = fetcher.NewFetcher(ethClient, rpcClient, n) }) It("retrieves the genesis header and first header", func(done Done) { diff --git a/pkg/core/node_info.go b/pkg/core/node_info.go index a3d91d84..dea37de7 100644 --- a/pkg/core/node_info.go +++ b/pkg/core/node_info.go @@ -16,10 +16,6 @@ package core -import ( - "fmt" -) - // NodeType is an enum to represent different node types type NodeType int @@ -38,22 +34,7 @@ const ( type Node struct { GenesisBlock string NetworkID string + ChainID uint64 ID string ClientName string } - -type ParityNodeInfo struct { - Track string - ParityVersion `json:"version"` - Hash string -} - -func (pn ParityNodeInfo) String() string { - return fmt.Sprintf("Parity/v%d.%d.%d/", pn.Major, pn.Minor, pn.Patch) -} - -type ParityVersion struct { - Major int - Minor int - Patch int -} diff --git a/pkg/fakes/mock_rpc_client.go b/pkg/fakes/mock_rpc_client.go index 96908efe..d615c527 100644 --- a/pkg/fakes/mock_rpc_client.go +++ b/pkg/fakes/mock_rpc_client.go @@ -115,18 +115,6 @@ func (client *MockRPCClient) CallContext(ctx context.Context, result interface{} if client.callContextErr != nil { return client.callContextErr } - 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" diff --git a/pkg/node/node.go b/pkg/node/node.go index 140f7a0a..7df66bf1 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -17,152 +17,33 @@ package node import ( - "context" - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/p2p" - log "github.com/sirupsen/logrus" + "github.com/spf13/viper" "github.com/vulcanize/eth-header-sync/pkg/core" ) -type IPropertiesReader interface { - NodeInfo() (id string, name string) - NetworkID() float64 - GenesisBlock() string -} - -type PropertiesReader struct { - client core.RPCClient -} - -type ParityClient struct { - PropertiesReader -} +// Env variables +const ( + ETH_NODE_ID = "ETH_NODE_ID" + ETH_CLIENT_NAME = "ETH_CLIENT_NAME" + ETH_GENESIS_BLOCK = "ETH_GENESIS_BLOCK" + ETH_NETWORK_ID = "ETH_NETWORK_ID" + ETH_CHAIN_ID = "ETH_CHAIN_ID" +) -type GethClient struct { - PropertiesReader -} +// MakeNode makes a node info object from env variables +func MakeNode() core.Node { + viper.BindEnv("ethereum.nodeID", ETH_NODE_ID) + viper.BindEnv("ethereum.clientName", ETH_CLIENT_NAME) + viper.BindEnv("ethereum.genesisBlock", ETH_GENESIS_BLOCK) + viper.BindEnv("ethereum.networkID", ETH_NETWORK_ID) + viper.BindEnv("ethereum.chainID", ETH_CHAIN_ID) -type InfuraClient struct { - PropertiesReader -} - -type GanacheClient struct { - PropertiesReader -} - -func MakeNode(rpcClient core.RPCClient) core.Node { - pr := makePropertiesReader(rpcClient) - id, name := pr.NodeInfo() return core.Node{ - GenesisBlock: pr.GenesisBlock(), - NetworkID: fmt.Sprintf("%f", pr.NetworkID()), - ID: id, - ClientName: name, - } -} - -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}} - case core.GANACHE: - return GanacheClient{PropertiesReader: PropertiesReader{client: client}} - default: - return PropertiesReader{client: client} - } -} - -func getNodeType(client core.RPCClient) core.NodeType { - // TODO: fix this - // This heuristics for figuring out the node type are not useful... - // for example we often port forward remote nodes to localhost - // and geth does not have to expose the admin api... - if strings.Contains(client.RPCPath(), "infura") { - return core.INFURA - } - if strings.Contains(client.RPCPath(), "127.0.0.1") || strings.Contains(client.RPCPath(), "localhost") { - return core.GANACHE - } - modules, _ := client.SupportedModules() - if _, ok := modules["admin"]; ok { - return core.GETH - } - return core.PARITY -} - -func (reader PropertiesReader) NetworkID() float64 { - var version string - err := reader.client.CallContext(context.Background(), &version, "net_version") - if err != nil { - log.Error(err) - } - networkID, _ := strconv.ParseFloat(version, 64) - return networkID -} - -func (reader PropertiesReader) GenesisBlock() string { - var header *types.Header - blockZero := "0x0" - includeTransactions := false - err := reader.client.CallContext(context.Background(), &header, "eth_getBlockByNumber", blockZero, includeTransactions) - if err != nil { - log.Error(err) - } - return header.Hash().Hex() -} - -func (reader PropertiesReader) NodeInfo() (string, string) { - var info p2p.NodeInfo - err := reader.client.CallContext(context.Background(), &info, "admin_nodeInfo") - if err != nil { - log.Error(err) - } - return info.ID, info.Name -} - -func (client ParityClient) NodeInfo() (string, string) { - nodeInfo := client.parityNodeInfo() - id := client.parityID() - return id, nodeInfo -} - -func (client InfuraClient) NodeInfo() (string, string) { - return "infura", "infura" -} - -func (client GanacheClient) NodeInfo() (string, string) { - return "ganache", "ganache" -} - -func (client ParityClient) parityNodeInfo() string { - var nodeInfo core.ParityNodeInfo - err := client.client.CallContext(context.Background(), &nodeInfo, "parity_versionInfo") - if err != nil { - log.Error(err) - } - return nodeInfo.String() -} - -func (client ParityClient) parityID() string { - var enodeID = regexp.MustCompile(`^enode://(.+)@.+$`) - var enodeURL string - err := client.client.CallContext(context.Background(), &enodeURL, "parity_enode") - if err != nil { - log.Error(err) - } - enode := enodeID.FindStringSubmatch(enodeURL) - if len(enode) < 2 { - return "" + ID: viper.GetString("ethereum.nodeID"), + ClientName: viper.GetString("ethereum.clientName"), + GenesisBlock: viper.GetString("ethereum.genesisBlock"), + NetworkID: viper.GetString("ethereum.networkID"), + ChainID: viper.GetUint64("ethereum.chainID"), } - return enode[1] } diff --git a/pkg/node/node_test.go b/pkg/node/node_test.go index 4a344166..00929f9d 100644 --- a/pkg/node/node_test.go +++ b/pkg/node/node_test.go @@ -17,103 +17,26 @@ package node_test import ( - "encoding/json" + "github.com/spf13/viper" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/vulcanize/eth-header-sync/pkg/core" - "github.com/vulcanize/eth-header-sync/pkg/fakes" "github.com/vulcanize/eth-header-sync/pkg/node" ) var EmpytHeaderHash = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" var _ = Describe("Node Info", func() { - Describe("Parity Node Info", func() { - It("verifies parity_versionInfo can be unmarshalled into ParityNodeInfo", func() { - var parityNodeInfo core.ParityNodeInfo - nodeInfoJSON := []byte( - `{ - "hash": "0x2ae8b4ca278dd7b896090366615fef81cbbbc0e0", - "track": "null", - "version": { - "major": 1, - "minor": 6, - "patch": 0 - } - }`) - json.Unmarshal(nodeInfoJSON, &parityNodeInfo) - Expect(parityNodeInfo.Hash).To(Equal("0x2ae8b4ca278dd7b896090366615fef81cbbbc0e0")) - Expect(parityNodeInfo.Track).To(Equal("null")) - Expect(parityNodeInfo.Major).To(Equal(1)) - Expect(parityNodeInfo.Minor).To(Equal(6)) - Expect(parityNodeInfo.Patch).To(Equal(0)) - }) - - It("Creates client string", func() { - parityNodeInfo := core.ParityNodeInfo{ - Track: "null", - ParityVersion: core.ParityVersion{ - Major: 1, - Minor: 6, - Patch: 0, - }, - Hash: "0x1232144j", - } - Expect(parityNodeInfo.String()).To(Equal("Parity/v1.6.0/")) - }) - - It("returns parity ID and client name for parity node", func() { - client := fakes.NewMockRPCClient() - - n := node.MakeNode(client) - Expect(n.ID).To(Equal("ParityNode")) - Expect(n.ClientName).To(Equal("Parity/v1.2.3/")) - }) - }) - It("returns the genesis block for any client", func() { - client := fakes.NewMockRPCClient() - n := node.MakeNode(client) + viper.Set("ethereum.genesisBlock", "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") + n := node.MakeNode() Expect(n.GenesisBlock).To(Equal(EmpytHeaderHash)) }) It("returns the network id for any client", func() { - client := fakes.NewMockRPCClient() - n := node.MakeNode(client) + viper.Set("ethereum.networkID", "1234.000000") + n := node.MakeNode() Expect(n.NetworkID).To(Equal("1234.000000")) }) - - It("returns geth ID and client name for geth node", func() { - client := fakes.NewMockRPCClient() - supportedModules := make(map[string]string) - supportedModules["admin"] = "ok" - client.SetSupporedModules(supportedModules) - - 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() { - client := fakes.NewMockRPCClient() - client.SetRPCPath("infura/path") - n := node.MakeNode(client) - Expect(n.ID).To(Equal("infura")) - Expect(n.ClientName).To(Equal("infura")) - }) - - It("returns local id and client name for Local node", func() { - client := fakes.NewMockRPCClient() - client.SetRPCPath("127.0.0.1") - n := node.MakeNode(client) - Expect(n.ID).To(Equal("ganache")) - Expect(n.ClientName).To(Equal("ganache")) - - client.SetRPCPath("localhost") - n = node.MakeNode(client) - Expect(n.ID).To(Equal("ganache")) - Expect(n.ClientName).To(Equal("ganache")) - }) }) From 9cfb912b6141d8328c4312270cf34527b0168285 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Thu, 10 Sep 2020 17:21:41 -0500 Subject: [PATCH 2/2] store chainID --- db/migrations/00001_create_nodes_table.sql | 3 ++- db/schema.sql | 5 +++-- environments/example.toml | 2 -- pkg/postgres/postgres.go | 11 ++++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/db/migrations/00001_create_nodes_table.sql b/db/migrations/00001_create_nodes_table.sql index 76db3d71..909d5789 100644 --- a/db/migrations/00001_create_nodes_table.sql +++ b/db/migrations/00001_create_nodes_table.sql @@ -5,7 +5,8 @@ CREATE TABLE nodes ( genesis_block VARCHAR(66), network_id VARCHAR, node_id VARCHAR(128), - CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id) + chain_id INTEGER, + CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id, chain_id) ); -- +goose Down diff --git a/db/schema.sql b/db/schema.sql index 10834144..dcf36c87 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -97,7 +97,8 @@ CREATE TABLE public.nodes ( client_name character varying, genesis_block character varying(66), network_id character varying, - node_id character varying(128) + node_id character varying(128), + chain_id integer ); @@ -171,7 +172,7 @@ ALTER TABLE ONLY public.headers -- ALTER TABLE ONLY public.nodes - ADD CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id); + ADD CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id, chain_id); -- diff --git a/environments/example.toml b/environments/example.toml index 021327ae..bb87d768 100644 --- a/environments/example.toml +++ b/environments/example.toml @@ -7,8 +7,6 @@ rpcPath = "/geth.ipc" [ethereum] - wsPath = "127.0.0.1:8546" # $ETH_WS_PATH - httpPath = "127.0.0.1:8545" # $ETH_HTTP_PATH nodeID = "arch1" # $ETH_NODE_ID clientName = "Geth" # $ETH_CLIENT_NAME genesisBlock = "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" # $ETH_GENESIS_BLOCK diff --git a/pkg/postgres/postgres.go b/pkg/postgres/postgres.go index d76fb82d..118552dd 100644 --- a/pkg/postgres/postgres.go +++ b/pkg/postgres/postgres.go @@ -61,16 +61,17 @@ func NewDB(databaseConfig config.Database, node core.Node) (*DB, error) { func (db *DB) CreateNode(node *core.Node) error { var nodeID int64 err := db.QueryRow( - `INSERT INTO nodes (genesis_block, network_id, node_id, client_name) - VALUES ($1, $2, $3, $4) - ON CONFLICT (genesis_block, network_id, node_id) + `INSERT INTO nodes (genesis_block, network_id, node_id, client_name, chain_id) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (genesis_block, network_id, node_id, chain_id) DO UPDATE SET genesis_block = $1, network_id = $2, node_id = $3, - client_name = $4 + client_name = $4, + chain_id = $5 RETURNING id`, - node.GenesisBlock, node.NetworkID, node.ID, node.ClientName).Scan(&nodeID) + node.GenesisBlock, node.NetworkID, node.ID, node.ClientName, node.ChainID).Scan(&nodeID) if err != nil { return ErrUnableToSetNode(err) }