mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-03 17:44:29 +00:00
436493350e
1. changes sentinel to use an http-like interface 2. moves hexutil, crypto/blake2b, metrics packages to erigon-lib
328 lines
9.5 KiB
Go
328 lines
9.5 KiB
Go
package commands
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/ledgerwatch/erigon-lib/metrics"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/holiman/uint256"
|
|
"github.com/ledgerwatch/log/v3"
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/commitment"
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/common/datadir"
|
|
"github.com/ledgerwatch/erigon-lib/common/dbg"
|
|
"github.com/ledgerwatch/erigon-lib/common/length"
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
kv2 "github.com/ledgerwatch/erigon-lib/kv/mdbx"
|
|
libstate "github.com/ledgerwatch/erigon-lib/state"
|
|
|
|
"github.com/ledgerwatch/erigon/cmd/utils"
|
|
"github.com/ledgerwatch/erigon/core"
|
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
|
"github.com/ledgerwatch/erigon/eth/ethconfig"
|
|
"github.com/ledgerwatch/erigon/node/nodecfg"
|
|
erigoncli "github.com/ledgerwatch/erigon/turbo/cli"
|
|
"github.com/ledgerwatch/erigon/turbo/debug"
|
|
)
|
|
|
|
func init() {
|
|
withDataDir(readDomains)
|
|
withChain(readDomains)
|
|
withHeimdall(readDomains)
|
|
withWorkers(readDomains)
|
|
withStartTx(readDomains)
|
|
|
|
rootCmd.AddCommand(readDomains)
|
|
}
|
|
|
|
// if trie variant is not hex, we could not have another rootHash with to verify it
|
|
var (
|
|
stepSize uint64
|
|
lastStep uint64
|
|
dirtySpaceThreshold = uint64(2 * 1024 * 1024 * 1024) /* threshold of dirty space in MDBX transaction that triggers a commit */
|
|
blockRootMismatchExpected bool
|
|
|
|
mxBlockExecutionTimer = metrics.GetOrCreateSummary("chain_execution_seconds")
|
|
mxCommitTook = metrics.GetOrCreateHistogram("domain_commit_took")
|
|
)
|
|
|
|
// write command to just seek and query state by addr and domain from state db and files (if any)
|
|
var readDomains = &cobra.Command{
|
|
Use: "read_domains",
|
|
Short: `Run block execution and commitment with Domains.`,
|
|
Example: "go run ./cmd/integration read_domains --datadir=... --verbosity=3",
|
|
ValidArgs: []string{"account", "storage", "code", "commitment"},
|
|
Args: cobra.ArbitraryArgs,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
logger := debug.SetupCobra(cmd, "integration")
|
|
ctx, _ := libcommon.RootContext()
|
|
cfg := &nodecfg.DefaultConfig
|
|
utils.SetNodeConfigCobra(cmd, cfg)
|
|
ethConfig := ðconfig.Defaults
|
|
ethConfig.Genesis = core.GenesisBlockByChainName(chain)
|
|
erigoncli.ApplyFlagsForEthConfigCobra(cmd.Flags(), ethConfig)
|
|
|
|
var readFromDomain string
|
|
var addrs [][]byte
|
|
for i := 0; i < len(args); i++ {
|
|
if i == 0 {
|
|
switch s := strings.ToLower(args[i]); s {
|
|
case "account", "storage", "code", "commitment":
|
|
readFromDomain = s
|
|
default:
|
|
logger.Error("invalid domain to read from", "arg", args[i])
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
addr, err := hex.DecodeString(strings.TrimPrefix(args[i], "0x"))
|
|
if err != nil {
|
|
logger.Warn("invalid address passed", "str", args[i], "at position", i, "err", err)
|
|
continue
|
|
}
|
|
addrs = append(addrs, addr)
|
|
}
|
|
|
|
dirs := datadir.New(datadirCli)
|
|
chainDb, err := openDB(dbCfg(kv.ChainDB, dirs.Chaindata), true, logger)
|
|
if err != nil {
|
|
logger.Error("Opening DB", "error", err)
|
|
return
|
|
}
|
|
defer chainDb.Close()
|
|
|
|
stateDb, err := kv2.NewMDBX(log.New()).Path(filepath.Join(dirs.DataDir, "statedb")).WriteMap().Open(ctx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer stateDb.Close()
|
|
|
|
if err := requestDomains(chainDb, stateDb, ctx, readFromDomain, addrs, logger); err != nil {
|
|
if !errors.Is(err, context.Canceled) {
|
|
logger.Error(err.Error())
|
|
}
|
|
return
|
|
}
|
|
},
|
|
}
|
|
|
|
func requestDomains(chainDb, stateDb kv.RwDB, ctx context.Context, readDomain string, addrs [][]byte, logger log.Logger) error {
|
|
trieVariant := commitment.ParseTrieVariant(commitmentTrie)
|
|
if trieVariant != commitment.VariantHexPatriciaTrie {
|
|
blockRootMismatchExpected = true
|
|
}
|
|
mode := libstate.ParseCommitmentMode(commitmentMode)
|
|
libstate.COMPARE_INDEXES = true
|
|
|
|
_, _, _, agg := newDomains(ctx, chainDb, stepSize, mode, trieVariant, logger)
|
|
defer agg.Close()
|
|
|
|
histTx, err := chainDb.BeginRo(ctx)
|
|
must(err)
|
|
defer histTx.Rollback()
|
|
|
|
stateTx, err := stateDb.BeginRw(ctx)
|
|
must(err)
|
|
defer stateTx.Rollback()
|
|
|
|
agg.SetTx(stateTx)
|
|
defer agg.StartWrites().FinishWrites()
|
|
|
|
latestBlock, latestTx, err := agg.SeekCommitment()
|
|
if err != nil && startTxNum != 0 {
|
|
return fmt.Errorf("failed to seek commitment to tx %d: %w", startTxNum, err)
|
|
}
|
|
if latestTx < startTxNum {
|
|
return fmt.Errorf("latest available tx to start is %d and its less than start tx %d", latestTx, startTxNum)
|
|
}
|
|
if latestTx > 0 {
|
|
logger.Info("aggregator files opened", "txn", latestTx, "block", latestBlock)
|
|
}
|
|
agg.SetTxNum(latestTx)
|
|
|
|
r := ReaderWrapper4{
|
|
roTx: histTx,
|
|
ac: agg.MakeContext(),
|
|
}
|
|
|
|
switch readDomain {
|
|
case "account":
|
|
for _, addr := range addrs {
|
|
acc, err := r.ReadAccountData(libcommon.BytesToAddress(addr))
|
|
if err != nil {
|
|
logger.Error("failed to read account", "addr", addr, "err", err)
|
|
continue
|
|
}
|
|
fmt.Printf("%x: nonce=%d balance=%d code=%x root=%x\n", addr, acc.Nonce, acc.Balance.Uint64(), acc.CodeHash, acc.Root)
|
|
}
|
|
case "storage":
|
|
for _, addr := range addrs {
|
|
a, s := libcommon.BytesToAddress(addr[:length.Addr]), libcommon.BytesToHash(addr[length.Addr:])
|
|
st, err := r.ReadAccountStorage(a, 0, &s)
|
|
if err != nil {
|
|
logger.Error("failed to read storage", "addr", a.String(), "key", s.String(), "err", err)
|
|
continue
|
|
}
|
|
fmt.Printf("%s %s -> %x\n", a.String(), s.String(), st)
|
|
}
|
|
case "code":
|
|
for _, addr := range addrs {
|
|
code, err := r.ReadAccountCode(libcommon.BytesToAddress(addr), 0, libcommon.Hash{})
|
|
if err != nil {
|
|
logger.Error("failed to read code", "addr", addr, "err", err)
|
|
continue
|
|
}
|
|
fmt.Printf("%s: %x\n", addr, code)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Implements StateReader and StateWriter
|
|
type ReaderWrapper4 struct {
|
|
roTx kv.Tx
|
|
ac *libstate.AggregatorContext
|
|
}
|
|
|
|
type WriterWrapper4 struct {
|
|
w *libstate.Aggregator
|
|
}
|
|
|
|
func (rw *ReaderWrapper4) SetTx(roTx kv.Tx, ctx *libstate.AggregatorContext) {
|
|
rw.roTx = roTx
|
|
rw.ac.Close()
|
|
rw.ac = ctx
|
|
}
|
|
|
|
func (rw *ReaderWrapper4) ReadAccountData(address libcommon.Address) (*accounts.Account, error) {
|
|
enc, err := rw.ac.ReadAccountData(address.Bytes(), rw.roTx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(enc) == 0 {
|
|
return nil, nil
|
|
}
|
|
var a accounts.Account
|
|
if err := accounts.DeserialiseV3(&a, enc); err != nil {
|
|
return nil, err
|
|
}
|
|
return &a, nil
|
|
}
|
|
|
|
func (rw *ReaderWrapper4) ReadAccountStorage(address libcommon.Address, incarnation uint64, key *libcommon.Hash) ([]byte, error) {
|
|
enc, err := rw.ac.ReadAccountStorage(address.Bytes(), key.Bytes(), rw.roTx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if enc == nil {
|
|
return nil, nil
|
|
}
|
|
if len(enc) == 1 && enc[0] == 0 {
|
|
return nil, nil
|
|
}
|
|
return enc, nil
|
|
}
|
|
|
|
func (rw *ReaderWrapper4) ReadAccountCode(address libcommon.Address, incarnation uint64, codeHash libcommon.Hash) ([]byte, error) {
|
|
return rw.ac.ReadAccountCode(address.Bytes(), rw.roTx)
|
|
}
|
|
|
|
func (rw *ReaderWrapper4) ReadAccountCodeSize(address libcommon.Address, incarnation uint64, codeHash libcommon.Hash) (int, error) {
|
|
return rw.ac.ReadAccountCodeSize(address.Bytes(), rw.roTx)
|
|
}
|
|
|
|
func (rw *ReaderWrapper4) ReadAccountIncarnation(address libcommon.Address) (uint64, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
func (ww *WriterWrapper4) UpdateAccountData(address libcommon.Address, original, account *accounts.Account) error {
|
|
value := accounts.SerialiseV3(account)
|
|
if err := ww.w.UpdateAccountData(address.Bytes(), value); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ww *WriterWrapper4) UpdateAccountCode(address libcommon.Address, incarnation uint64, codeHash libcommon.Hash, code []byte) error {
|
|
if err := ww.w.UpdateAccountCode(address.Bytes(), code); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ww *WriterWrapper4) DeleteAccount(address libcommon.Address, original *accounts.Account) error {
|
|
if err := ww.w.DeleteAccount(address.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ww *WriterWrapper4) WriteAccountStorage(address libcommon.Address, incarnation uint64, key *libcommon.Hash, original, value *uint256.Int) error {
|
|
if err := ww.w.WriteAccountStorage(address.Bytes(), key.Bytes(), value.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ww *WriterWrapper4) CreateContract(address libcommon.Address) error {
|
|
return nil
|
|
}
|
|
|
|
type stat4 struct {
|
|
prevBlock uint64
|
|
blockNum uint64
|
|
hits uint64
|
|
misses uint64
|
|
hitMissRatio float64
|
|
blockSpeed float64
|
|
txSpeed float64
|
|
prevTxNum uint64
|
|
txNum uint64
|
|
prevTime time.Time
|
|
mem runtime.MemStats
|
|
startedAt time.Time
|
|
}
|
|
|
|
func (s *stat4) print(aStats libstate.FilesStats, logger log.Logger) {
|
|
totalFiles := aStats.FilesCount
|
|
totalDatSize := aStats.DataSize
|
|
totalIdxSize := aStats.IdxSize
|
|
|
|
logger.Info("Progress", "block", s.blockNum, "blk/s", s.blockSpeed, "tx", s.txNum, "txn/s", s.txSpeed, "state files", totalFiles,
|
|
"total dat", libcommon.ByteCount(totalDatSize), "total idx", libcommon.ByteCount(totalIdxSize),
|
|
"hit ratio", s.hitMissRatio, "hits+misses", s.hits+s.misses,
|
|
"alloc", libcommon.ByteCount(s.mem.Alloc), "sys", libcommon.ByteCount(s.mem.Sys),
|
|
)
|
|
}
|
|
|
|
func (s *stat4) delta(blockNum, txNum uint64) *stat4 {
|
|
currentTime := time.Now()
|
|
dbg.ReadMemStats(&s.mem)
|
|
|
|
interval := currentTime.Sub(s.prevTime).Seconds()
|
|
s.blockNum = blockNum
|
|
s.blockSpeed = float64(s.blockNum-s.prevBlock) / interval
|
|
s.txNum = txNum
|
|
s.txSpeed = float64(s.txNum-s.prevTxNum) / interval
|
|
s.prevBlock = blockNum
|
|
s.prevTxNum = txNum
|
|
s.prevTime = currentTime
|
|
if s.startedAt.IsZero() {
|
|
s.startedAt = currentTime
|
|
}
|
|
|
|
total := s.hits + s.misses
|
|
if total > 0 {
|
|
s.hitMissRatio = float64(s.hits) / float64(total)
|
|
}
|
|
return s
|
|
}
|