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

core: implement network ID detection check on startup #301

Merged
merged 12 commits into from
Jul 24, 2019
33 changes: 33 additions & 0 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"encoding/json"
"fmt"
"math/big"
"os"
"path/filepath"
"sync"
Expand Down Expand Up @@ -119,6 +120,12 @@ func New(config Config) (*App, error) {
return nil, err
}

// Check if the DB has been previously intialized with a different networkId
err = initNetworkId(config.EthereumNetworkID, meshDB)
hrharder marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}

// Initialize the ETH client, which will be used by various watchers.
ethClient, err := ethclient.Dial(config.EthereumRPCURL)
if err != nil {
Expand Down Expand Up @@ -250,6 +257,32 @@ func initPrivateKey(path string) (p2pcrypto.PrivKey, error) {
return nil, err
}

func initNetworkId(networkID int, meshDB *meshdb.MeshDB) error {
hrharder marked this conversation as resolved.
Show resolved Hide resolved
var metadata meshdb.Metadata
err := meshDB.Metadata.FindByID([]byte{0}, &metadata)
hrharder marked this conversation as resolved.
Show resolved Hide resolved

if _, ok := err.(db.NotFoundError); ok {
// No stored metadata found (first startup)
setMetadata := meshdb.Metadata{EthereumNetworkID: big.NewInt(int64(networkID))}
err = meshDB.Metadata.Insert(&setMetadata)
if err != nil {
return err
}
return nil
} else if err != nil {
return err
}
hrharder marked this conversation as resolved.
Show resolved Hide resolved

// on subsequent startups, verify we are on the same network
loadedNetworkID := metadata.EthereumNetworkID.Int64()
if loadedNetworkID != int64(networkID) {
err := fmt.Errorf("expected networkID to be %d but got %d", loadedNetworkID, networkID)
log.WithError(err).Error("Mesh previously started on different Ethereum network; switch networks or remove DB")
return err
}
return nil
}

func (app *App) Start() error {
go func() {
err := app.node.Start()
Expand Down
28 changes: 28 additions & 0 deletions core/core_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package core

import (
"testing"

"github.com/stretchr/testify/assert"

hrharder marked this conversation as resolved.
Show resolved Hide resolved
"github.com/0xProject/0x-mesh/meshdb"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)

func TestEthereumNetworkDetection(t *testing.T) {
meshDB, err := meshdb.NewMeshDB("/tmp/meshdb_testing/" + uuid.New().String())
require.NoError(t, err)

// simulate starting up on mainnet
err = initNetworkId(1, meshDB)
require.NoError(t, err)

// simulate restart on same network
err = initNetworkId(1, meshDB)
require.NoError(t, err)

// should error when attempting to start on different network
err = initNetworkId(2, meshDB)
assert.Error(t, err)
}
30 changes: 30 additions & 0 deletions meshdb/meshdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,22 @@ func (o Order) ID() []byte {
return o.Hash.Bytes()
}

// Metadata is the database representation of MeshDB instance metadata
type Metadata struct {
EthereumNetworkID *big.Int
hrharder marked this conversation as resolved.
Show resolved Hide resolved
}

// ID returns the id used for the metadata collection (one per DB)
func (m Metadata) ID() []byte {
return []byte{0}
}

// MeshDB instantiates the DB connection and creates all the collections used by the application
type MeshDB struct {
database *db.DB
MiniHeaders *MiniHeadersCollection
Orders *OrdersCollection
Metadata *MetadataCollection
}

// MiniHeadersCollection represents a DB collection of mini Ethereum block headers
Expand All @@ -67,6 +78,11 @@ type OrdersCollection struct {
IsRemovedIndex *db.Index
}

// MetadataCollection represents a DB collection used to store instance metadata
type MetadataCollection struct {
*db.Collection
}

// NewMeshDB instantiates a new MeshDB instance
func NewMeshDB(path string) (*MeshDB, error) {
database, err := db.Open(path)
Expand All @@ -84,10 +100,16 @@ func NewMeshDB(path string) (*MeshDB, error) {
return nil, err
}

metadata, err := setupMetadata(database)
if err != nil {
return nil, err
}

return &MeshDB{
database: database,
MiniHeaders: miniHeaders,
Orders: orders,
Metadata: metadata,
hrharder marked this conversation as resolved.
Show resolved Hide resolved
}, nil
}

Expand Down Expand Up @@ -170,6 +192,14 @@ func setupMiniHeaders(database *db.DB) (*MiniHeadersCollection, error) {
}, nil
}

func setupMetadata(database *db.DB) (*MetadataCollection, error) {
col, err := database.NewCollection("metadata", &Metadata{})
if err != nil {
return nil, err
}
return &MetadataCollection{col}, nil
}

// Close closes the database connection
func (m *MeshDB) Close() {
m.database.Close()
Expand Down