erigon-pulse/cmd/integration/commands/state_domains.go
a 436493350e
Sentinel refactor (#8296)
1. changes sentinel to use an http-like interface

2. moves hexutil, crypto/blake2b, metrics packages to erigon-lib
2023-10-22 01:17:18 +02:00

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 := &ethconfig.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
}