[NOD-27] If node started with new sub-network - require to delete the database before proceeding (#198)

This commit is contained in:
Ori Newman 2019-03-10 17:31:53 +02:00 committed by Svarog
parent 1e447432a7
commit d62279192a
4 changed files with 86 additions and 2 deletions

View File

@ -8,6 +8,8 @@ import (
"errors"
"fmt"
"math"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
@ -19,6 +21,7 @@ import (
"github.com/daglabs/btcd/dagconfig"
"github.com/daglabs/btcd/dagconfig/daghash"
"github.com/daglabs/btcd/database"
"github.com/daglabs/btcd/txscript"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/util/subnetworkid"
@ -864,6 +867,49 @@ func testErrorThroughPatching(t *testing.T, expectedErrorMessage string, targetF
}
}
func TestNew(t *testing.T) {
// Create the root directory for test databases.
if !fileExists(testDbRoot) {
if err := os.MkdirAll(testDbRoot, 0700); err != nil {
t.Fatalf("unable to create test db "+
"root: %s", err)
}
}
dbPath := filepath.Join(testDbRoot, "TestNew")
_ = os.RemoveAll(dbPath)
db, err := database.Create(testDbType, dbPath, blockDataNet)
if err != nil {
t.Fatalf("error creating db: %s", err)
}
defer func() {
db.Close()
os.RemoveAll(dbPath)
os.RemoveAll(testDbRoot)
}()
config := &Config{
DAGParams: &dagconfig.SimNetParams,
SubnetworkID: subnetworkid.SubnetworkIDSupportsAll,
DB: db,
TimeSource: NewMedianTime(),
SigCache: txscript.NewSigCache(1000),
}
_, err = New(config)
if err != nil {
t.Fatalf("failed to create dag instance: %s", err)
}
config.SubnetworkID = &subnetworkid.SubnetworkID{0xff}
_, err = New(config)
expectedErrorMessage := fmt.Sprintf("Cannot start btcd with subnetwork ID %s because"+
" its database is already built with subnetwork ID %s. If you"+
" want to switch to a new database, please reset the"+
" database by starting btcd with --reset-db flag", config.SubnetworkID, subnetworkid.SubnetworkIDSupportsAll)
if err.Error() != expectedErrorMessage {
t.Errorf("Unexpected error. Expected error '%s' but got '%s'", expectedErrorMessage, err)
}
}
func TestValidateFeeTransaction(t *testing.T) {
params := dagconfig.SimNetParams
params.K = 1

View File

@ -14,6 +14,7 @@ import (
"github.com/daglabs/btcd/dagconfig/daghash"
"github.com/daglabs/btcd/database"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/util/subnetworkid"
"github.com/daglabs/btcd/wire"
)
@ -57,6 +58,10 @@ var (
// subnetwork registry.
subnetworksBucketName = []byte("subnetworks")
// localSubnetworkKeyName is the name of the db key used to store the
// node's local subnetwork ID.
localSubnetworkKeyName = []byte("localsubnetworkidkey")
// byteOrder is the preferred byte order used for serializing numeric
// fields for storage in the database.
byteOrder = binary.LittleEndian
@ -480,6 +485,10 @@ func (dag *BlockDAG) createDAGState() error {
if err != nil {
return err
}
if err := dbPutLocalSubnetworkID(dbTx, dag.subnetworkID); err != nil {
return err
}
return nil
})
@ -489,15 +498,30 @@ func (dag *BlockDAG) createDAGState() error {
return nil
}
func dbPutLocalSubnetworkID(dbTx database.Tx, subnetworkID *subnetworkid.SubnetworkID) error {
return dbTx.Metadata().Put(localSubnetworkKeyName, subnetworkID[:])
}
// initDAGState attempts to load and initialize the DAG state from the
// database. When the db does not yet contain any DAG state, both it and the
// DAG state are initialized to the genesis block.
func (dag *BlockDAG) initDAGState() error {
// Determine the state of the chain database. We may need to initialize
// Determine the state of the DAG database. We may need to initialize
// everything from scratch or upgrade certain buckets.
var initialized bool
err := dag.db.View(func(dbTx database.Tx) error {
initialized = dbTx.Metadata().Get(dagStateKeyName) != nil
if initialized {
localSubnetworkIDBytes := dbTx.Metadata().Get(localSubnetworkKeyName)
localSubnetworkID := &subnetworkid.SubnetworkID{}
localSubnetworkID.SetBytes(localSubnetworkIDBytes)
if !localSubnetworkID.IsEqual(dag.subnetworkID) {
return fmt.Errorf("Cannot start btcd with subnetwork ID %s because"+
" its database is already built with subnetwork ID %s. If you"+
" want to switch to a new database, please reset the"+
" database by starting btcd with --reset-db flag", dag.subnetworkID, localSubnetworkID)
}
}
return nil
})
if err != nil {

13
btcd.go
View File

@ -106,6 +106,14 @@ func btcdMain(serverChan chan<- *server.Server) error {
return nil
}
if cfg.ResetDatabase {
err := removeDatabase()
if err != nil {
btcdLog.Errorf("%s", err)
return err
}
}
// Load the block database.
db, err := loadBlockDB()
if err != nil {
@ -179,6 +187,11 @@ func btcdMain(serverChan chan<- *server.Server) error {
return nil
}
func removeDatabase() error {
dbPath := blockDbPath(cfg.DbType)
return os.RemoveAll(dbPath)
}
// removeRegressionDB removes the existing regression test database if running
// in regression test mode and it already exists.
func removeRegressionDB(dbPath string) error {

View File

@ -140,7 +140,7 @@ type configFlags struct {
SimNet bool `long:"simnet" description:"Use the simulation test network"`
AddCheckpoints []string `long:"addcheckpoint" description:"Add a custom checkpoint. Format: '<height>:<hash>'"`
DisableCheckpoints bool `long:"nocheckpoints" description:"Disable built-in checkpoints. Don't do this unless you know what you're doing."`
DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"`
DbType string `long:"dbtype" description:"Database backend to use for the Block DAG"`
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"`
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`
@ -167,6 +167,7 @@ type configFlags struct {
RelayNonStd bool `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."`
RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."`
Subnetwork string `long:"subnetwork" description:"If subnetwork ID != 0, than node will request and process only payloads from specified subnetwork. And if subnetwork ID is 0, than payloads of all subnetworks are processed. Subnetworks with IDs 3 through 255 are reserved for future use and are currently not allowed."`
ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."`
}
// Config defines the configuration options for btcd.