mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-27 22:28:21 +00:00
171 lines
4.3 KiB
Go
171 lines
4.3 KiB
Go
package commands
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
kv2 "github.com/ledgerwatch/erigon-lib/kv/mdbx"
|
|
"github.com/ledgerwatch/erigon/common"
|
|
"github.com/ledgerwatch/erigon/consensus/ethash"
|
|
"github.com/ledgerwatch/erigon/core"
|
|
"github.com/ledgerwatch/erigon/core/rawdb"
|
|
"github.com/ledgerwatch/erigon/core/state"
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
"github.com/ledgerwatch/erigon/core/vm"
|
|
"github.com/ledgerwatch/erigon/eth/stagedsync"
|
|
datadir2 "github.com/ledgerwatch/erigon/node/nodecfg/datadir"
|
|
"github.com/ledgerwatch/erigon/params"
|
|
"github.com/ledgerwatch/erigon/turbo/trie"
|
|
"github.com/ledgerwatch/log/v3"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func init() {
|
|
withBlock(stateRootCmd)
|
|
withDataDir(stateRootCmd)
|
|
rootCmd.AddCommand(stateRootCmd)
|
|
}
|
|
|
|
var stateRootCmd = &cobra.Command{
|
|
Use: "stateroot",
|
|
Short: "Exerimental command to re-execute blocks from beginning and compute state root",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
logger := log.New()
|
|
return StateRoot(genesis, logger, block, datadir)
|
|
},
|
|
}
|
|
|
|
func StateRoot(genesis *core.Genesis, logger log.Logger, blockNum uint64, datadir string) error {
|
|
sigs := make(chan os.Signal, 1)
|
|
interruptCh := make(chan bool, 1)
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
<-sigs
|
|
interruptCh <- true
|
|
}()
|
|
dirs := datadir2.New(datadir)
|
|
historyDb, err := kv2.NewMDBX(logger).Path(dirs.Chaindata).Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer historyDb.Close()
|
|
ctx := context.Background()
|
|
historyTx, err1 := historyDb.BeginRo(ctx)
|
|
if err1 != nil {
|
|
return err1
|
|
}
|
|
defer historyTx.Rollback()
|
|
stateDbPath := filepath.Join(datadir, "staterootdb")
|
|
if _, err = os.Stat(stateDbPath); err != nil {
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
return err
|
|
}
|
|
} else if err = os.RemoveAll(stateDbPath); err != nil {
|
|
return err
|
|
}
|
|
db, err2 := kv2.NewMDBX(logger).Path(stateDbPath).Open()
|
|
if err2 != nil {
|
|
return err2
|
|
}
|
|
defer db.Close()
|
|
chainConfig := genesis.Config
|
|
vmConfig := vm.Config{}
|
|
|
|
noOpWriter := state.NewNoopWriter()
|
|
interrupt := false
|
|
block := uint64(0)
|
|
var rwTx kv.RwTx
|
|
defer func() {
|
|
rwTx.Rollback()
|
|
}()
|
|
if rwTx, err = db.BeginRw(ctx); err != nil {
|
|
return err
|
|
}
|
|
_, genesisIbs, err4 := genesis.ToBlock()
|
|
if err4 != nil {
|
|
return err4
|
|
}
|
|
w := state.NewPlainStateWriter(rwTx, nil, 0)
|
|
if err = genesisIbs.CommitBlock(¶ms.Rules{}, w); err != nil {
|
|
return fmt.Errorf("cannot write state: %w", err)
|
|
}
|
|
if err = rwTx.Commit(); err != nil {
|
|
return err
|
|
}
|
|
var tx kv.Tx
|
|
defer func() {
|
|
if tx != nil {
|
|
tx.Rollback()
|
|
}
|
|
}()
|
|
for !interrupt {
|
|
block++
|
|
if block >= blockNum {
|
|
break
|
|
}
|
|
blockHash, err := rawdb.ReadCanonicalHash(historyTx, block)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var b *types.Block
|
|
b, _, err = rawdb.ReadBlockWithSenders(historyTx, blockHash, block)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if b == nil {
|
|
break
|
|
}
|
|
if tx, err = db.BeginRo(ctx); err != nil {
|
|
return err
|
|
}
|
|
if rwTx, err = db.BeginRw(ctx); err != nil {
|
|
return err
|
|
}
|
|
w = state.NewPlainStateWriter(rwTx, nil, block)
|
|
r := state.NewPlainStateReader(tx)
|
|
intraBlockState := state.New(r)
|
|
getHeader := func(hash common.Hash, number uint64) *types.Header { return rawdb.ReadHeader(historyTx, hash, number) }
|
|
if _, err = runBlock(ethash.NewFullFaker(), intraBlockState, noOpWriter, w, chainConfig, getHeader, nil, b, vmConfig, false); err != nil {
|
|
return fmt.Errorf("block %d: %w", block, err)
|
|
}
|
|
if block+1 == blockNum {
|
|
if err = rwTx.ClearBucket(kv.HashedAccounts); err != nil {
|
|
return err
|
|
}
|
|
if err = rwTx.ClearBucket(kv.HashedStorage); err != nil {
|
|
return err
|
|
}
|
|
if err = stagedsync.PromoteHashedStateCleanly("hashedstate", rwTx, stagedsync.StageHashStateCfg(nil, dirs, false, nil, nil), ctx); err != nil {
|
|
return err
|
|
}
|
|
var root common.Hash
|
|
root, err = trie.CalcRoot("genesis", rwTx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("root for block %d=[%x]\n", block, root)
|
|
}
|
|
if block%1000 == 0 {
|
|
log.Info("Processed", "blocks", block)
|
|
}
|
|
// Check for interrupts
|
|
select {
|
|
case interrupt = <-interruptCh:
|
|
fmt.Println("interrupted, please wait for cleanup...")
|
|
default:
|
|
}
|
|
tx.Rollback()
|
|
if err = rwTx.Commit(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|