@ -5,13 +5,16 @@ import (
"fmt"
"fmt"
"os"
"os"
"os/signal"
"os/signal"
"path"
"strings"
"strings"
ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/config"
"github.com/hermeznetwork/hermez-node/config"
dbUtils "github.com/hermeznetwork/hermez-node/db"
dbUtils "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/db/historydb"
"github.com/hermeznetwork/hermez-node/db/historydb"
"github.com/hermeznetwork/hermez-node/db/kvdb"
"github.com/hermeznetwork/hermez-node/db/l2db"
"github.com/hermeznetwork/hermez-node/db/l2db"
"github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/node"
"github.com/hermeznetwork/hermez-node/node"
@ -72,6 +75,86 @@ func cmdImportKey(c *cli.Context) error {
return nil
return nil
}
}
func resetStateDBs ( cfg * Config , batchNum common . BatchNum ) error {
log . Infof ( "Reset Synchronizer StateDB to batchNum %v..." , batchNum )
// Manually make a checkpoint from batchNum to current to force current
// to be a valid checkpoint. This is useful because in case of a
// crash, current can be corrupted and the first thing that
// `kvdb.NewKVDB` does is read the current checkpoint, which wouldn't
// succeed in case of corruption.
dbPath := cfg . node . StateDB . Path
source := path . Join ( dbPath , fmt . Sprintf ( "%s%d" , kvdb . PathBatchNum , batchNum ) )
current := path . Join ( dbPath , kvdb . PathCurrent )
last := path . Join ( dbPath , kvdb . PathLast )
if err := os . RemoveAll ( last ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "os.RemoveAll: %w" , err ) )
}
if batchNum == 0 {
if err := os . RemoveAll ( current ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "os.RemoveAll: %w" , err ) )
}
} else {
if err := kvdb . PebbleMakeCheckpoint ( source , current ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "kvdb.PebbleMakeCheckpoint: %w" , err ) )
}
}
db , err := kvdb . NewKVDB ( kvdb . Config {
Path : dbPath ,
NoGapsCheck : true ,
NoLast : true ,
} )
if err != nil {
return tracerr . Wrap ( fmt . Errorf ( "kvdb.NewKVDB: %w" , err ) )
}
if err := db . Reset ( batchNum ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "db.Reset: %w" , err ) )
}
if cfg . mode == node . ModeCoordinator {
log . Infof ( "Wipe Coordinator StateDBs..." )
// We wipe the Coordinator StateDBs entirely (by deleting
// current and resetting to batchNum 0) because the Coordinator
// StateDBs are always reset from Synchronizer when the
// coordinator pipeline starts.
dbPath := cfg . node . Coordinator . TxSelector . Path
current := path . Join ( dbPath , kvdb . PathCurrent )
if err := os . RemoveAll ( current ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "os.RemoveAll: %w" , err ) )
}
db , err := kvdb . NewKVDB ( kvdb . Config {
Path : dbPath ,
NoGapsCheck : true ,
NoLast : true ,
} )
if err != nil {
return tracerr . Wrap ( fmt . Errorf ( "kvdb.NewKVDB: %w" , err ) )
}
if err := db . Reset ( 0 ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "db.Reset: %w" , err ) )
}
dbPath = cfg . node . Coordinator . BatchBuilder . Path
current = path . Join ( dbPath , kvdb . PathCurrent )
if err := os . RemoveAll ( current ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "os.RemoveAll: %w" , err ) )
}
db , err = kvdb . NewKVDB ( kvdb . Config {
Path : dbPath ,
NoGapsCheck : true ,
NoLast : true ,
} )
if err != nil {
return tracerr . Wrap ( fmt . Errorf ( "statedb.NewKVDB: %w" , err ) )
}
if err := db . Reset ( 0 ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "db.Reset: %w" , err ) )
}
}
return nil
}
func cmdWipeSQL ( c * cli . Context ) error {
func cmdWipeSQL ( c * cli . Context ) error {
_cfg , err := parseCli ( c )
_cfg , err := parseCli ( c )
if err != nil {
if err != nil {
@ -80,7 +163,8 @@ func cmdWipeSQL(c *cli.Context) error {
cfg := _cfg . node
cfg := _cfg . node
yes := c . Bool ( flagYes )
yes := c . Bool ( flagYes )
if ! yes {
if ! yes {
fmt . Print ( "*WARNING* Are you sure you want to delete the SQL DB? [y/N]: " )
fmt . Print ( "*WARNING* Are you sure you want to delete " +
"the SQL DB and StateDBs? [y/N]: " )
var input string
var input string
if _ , err := fmt . Scanln ( & input ) ; err != nil {
if _ , err := fmt . Scanln ( & input ) ; err != nil {
return tracerr . Wrap ( err )
return tracerr . Wrap ( err )
@ -102,7 +186,12 @@ func cmdWipeSQL(c *cli.Context) error {
}
}
log . Info ( "Wiping SQL DB..." )
log . Info ( "Wiping SQL DB..." )
if err := dbUtils . MigrationsDown ( db . DB ) ; err != nil {
if err := dbUtils . MigrationsDown ( db . DB ) ; err != nil {
return tracerr . Wrap ( err )
return tracerr . Wrap ( fmt . Errorf ( "dbUtils.MigrationsDown: %w" , err ) )
}
log . Info ( "Wiping StateDBs..." )
if err := resetStateDBs ( _cfg , 0 ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "resetStateDBs: %w" , err ) )
}
}
return nil
return nil
}
}
@ -201,6 +290,11 @@ func cmdDiscard(c *cli.Context) error {
return tracerr . Wrap ( fmt . Errorf ( "l2DB.Reorg: %w" , err ) )
return tracerr . Wrap ( fmt . Errorf ( "l2DB.Reorg: %w" , err ) )
}
}
log . Info ( "Resetting StateDBs..." )
if err := resetStateDBs ( _cfg , batchNum ) ; err != nil {
return tracerr . Wrap ( fmt . Errorf ( "resetStateDBs: %w" , err ) )
}
return nil
return nil
}
}
@ -288,7 +382,7 @@ func main() {
{
{
Name : "wipesql" ,
Name : "wipesql" ,
Aliases : [ ] string { } ,
Aliases : [ ] string { } ,
Usage : "Wipe the SQL DB (HistoryDB and L2DB), " +
Usage : "Wipe the SQL DB (HistoryDB and L2DB) and the StateDBs , " +
"leaving the DB in a clean state" ,
"leaving the DB in a clean state" ,
Action : cmdWipeSQL ,
Action : cmdWipeSQL ,
Flags : [ ] cli . Flag {
Flags : [ ] cli . Flag {