Skip to content
This repository has been archived by the owner on Oct 20, 2021. It is now read-only.

Commit

Permalink
Merge pull request #7 from vulcanize/fix
Browse files Browse the repository at this point in the history
load node info from config
  • Loading branch information
i-norden authored Sep 10, 2020
2 parents c893a1c + 9cfb912 commit 8b0232a
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 265 deletions.
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
3 changes: 2 additions & 1 deletion db/migrations/00001_create_nodes_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions db/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
);


Expand Down Expand Up @@ -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);


--
Expand Down
7 changes: 7 additions & 0 deletions environments/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@

[client]
rpcPath = "/geth.ipc"

[ethereum]
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
4 changes: 2 additions & 2 deletions integration_test/header_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
21 changes: 1 addition & 20 deletions pkg/core/node_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@

package core

import (
"fmt"
)

// NodeType is an enum to represent different node types
type NodeType int

Expand All @@ -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
}
12 changes: 0 additions & 12 deletions pkg/fakes/mock_rpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
161 changes: 21 additions & 140 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
87 changes: 5 additions & 82 deletions pkg/node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
})
})
Loading

0 comments on commit 8b0232a

Please sign in to comment.