From eb6a16860325891bbcdf9315840bdcd75746fa00 Mon Sep 17 00:00:00 2001 From: ledgerwatch <akhounov@gmail.com> Date: Sat, 12 Feb 2022 00:06:57 +0000 Subject: [PATCH] [erigon2] Chain history and bitmap indices (#3437) * First update * Update to latest erigon-lib * Fix lint * Update * Update * Update * Add history2 command * Updates * Update erigon-lib Co-authored-by: Alexey Sharp <alexeysharp@Alexeys-iMac.local> Co-authored-by: Alex Sharp <alexsharp@Alexs-MacBook-Pro.local> --- cmd/state/commands/erigon2.go | 17 ++- cmd/state/commands/history2.go | 220 +++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- 4 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 cmd/state/commands/history2.go diff --git a/cmd/state/commands/erigon2.go b/cmd/state/commands/erigon2.go index 9440169553..6d637f3a74 100644 --- a/cmd/state/commands/erigon2.go +++ b/cmd/state/commands/erigon2.go @@ -38,6 +38,7 @@ const ( var ( commitmentFrequency int // How many blocks to skip between calculating commitment changesets bool + commitments bool ) func init() { @@ -45,6 +46,7 @@ func init() { withDatadir(erigon2Cmd) erigon2Cmd.Flags().BoolVar(&changesets, "changesets", false, "set to true to generate changesets") erigon2Cmd.Flags().IntVar(&commitmentFrequency, "commfreq", 625, "how many blocks to skip between calculating commitment") + erigon2Cmd.Flags().BoolVar(&commitments, "commitments", false, "set to true to calculate commitments") rootCmd.AddCommand(erigon2Cmd) } @@ -103,6 +105,7 @@ func Erigon2(genesis *core.Genesis, logger log.Logger) error { } defer agg.Close() agg.GenerateChangesets(changesets) + agg.Commitments(commitments) chainConfig := genesis.Config vmConfig := vm.Config{} @@ -124,14 +127,18 @@ func Erigon2(genesis *core.Genesis, logger log.Logger) error { if err = w.FinishTx(0, false); err != nil { return err } - if rootHash, err = w.ComputeCommitment(false); err != nil { - return err + if commitments { + if rootHash, err = w.ComputeCommitment(false); err != nil { + return err + } } if err = w.Aggregate(false); err != nil { return err } - if !bytes.Equal(rootHash, genBlock.Header().Root[:]) { - return fmt.Errorf("root hash mismatch for genesis block, expected [%x], was [%x]", genBlock.Header().Root[:], rootHash) + if commitments { + if !bytes.Equal(rootHash, genBlock.Header().Root[:]) { + return fmt.Errorf("root hash mismatch for genesis block, expected [%x], was [%x]", genBlock.Header().Root[:], rootHash) + } } } var txNum uint64 = 1 @@ -197,7 +204,7 @@ func Erigon2(genesis *core.Genesis, logger log.Logger) error { log.Info(fmt.Sprintf("interrupted, please wait for cleanup, next time start with --block %d", blockNum)) default: } - if interrupt || blockNum%uint64(commitmentFrequency) == 0 { + if commitments && (interrupt || blockNum%uint64(commitmentFrequency) == 0) { if rootHash, err = w.ComputeCommitment(trace /* trace */); err != nil { return err } diff --git a/cmd/state/commands/history2.go b/cmd/state/commands/history2.go new file mode 100644 index 0000000000..dae5b5f4f5 --- /dev/null +++ b/cmd/state/commands/history2.go @@ -0,0 +1,220 @@ +package commands + +import ( + "context" + "fmt" + "os" + "os/signal" + "path" + "syscall" + "time" + + "github.com/ledgerwatch/erigon-lib/aggregator" + kv2 "github.com/ledgerwatch/erigon-lib/kv/mdbx" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/consensus/misc" + "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/types/accounts" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/log/v3" + "github.com/spf13/cobra" +) + +func init() { + withBlock(history2Cmd) + withDatadir(history2Cmd) + rootCmd.AddCommand(history2Cmd) +} + +var history2Cmd = &cobra.Command{ + Use: "history2", + Short: "Exerimental command to re-execute historical transactions in erigon2 format", + RunE: func(cmd *cobra.Command, args []string) error { + logger := log.New() + return History2(genesis, logger) + }, +} + +func History2(genesis *core.Genesis, logger log.Logger) error { + sigs := make(chan os.Signal, 1) + interruptCh := make(chan bool, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + go func() { + <-sigs + interruptCh <- true + }() + historyDb, err := kv2.NewMDBX(logger).Path(path.Join(datadir, "chaindata")).Open() + if err != nil { + return fmt.Errorf("opening chaindata as read only: %v", err) + } + defer historyDb.Close() + ctx := context.Background() + historyTx, err1 := historyDb.BeginRo(ctx) + if err1 != nil { + return err1 + } + defer historyTx.Rollback() + aggPath := path.Join(datadir, "aggregator") + h, err3 := aggregator.NewHistory(aggPath, 499_999, aggregationStep) + if err3 != nil { + return fmt.Errorf("create history: %w", err3) + } + defer h.Close() + chainConfig := genesis.Config + vmConfig := vm.Config{} + + interrupt := false + blockNum := block + var txNum uint64 = 1 + trace := false + logEvery := time.NewTicker(logInterval) + defer logEvery.Stop() + prevBlock := blockNum + prevTime := time.Now() + for !interrupt { + select { + default: + case <-logEvery.C: + currentTime := time.Now() + interval := currentTime.Sub(prevTime) + speed := float64(blockNum-prevBlock) / (float64(interval) / float64(time.Second)) + prevBlock = blockNum + prevTime = currentTime + log.Info("Progress", "block", blockNum, "blk/s", speed) + } + blockNum++ + blockHash, err := rawdb.ReadCanonicalHash(historyTx, blockNum) + if err != nil { + return err + } + var b *types.Block + b, _, err = rawdb.ReadBlockWithSenders(historyTx, blockHash, blockNum) + if err != nil { + return err + } + if b == nil { + break + } + r := h.MakeHistoryReader() + readWrapper := &HistoryWrapper{r: r} + //readWrapper.trace = blockNum == 999_999 + writeWrapper := state.NewNoopWriter() + getHeader := func(hash common.Hash, number uint64) *types.Header { return rawdb.ReadHeader(historyTx, hash, number) } + if txNum, _, err = runHistory2(trace, blockNum, txNum, readWrapper, writeWrapper, chainConfig, getHeader, b, vmConfig); err != nil { + return fmt.Errorf("block %d: %w", blockNum, err) + } + txNum++ + // Check for interrupts + select { + case interrupt = <-interruptCh: + log.Info(fmt.Sprintf("interrupted, please wait for cleanup, next time start with --block %d", blockNum)) + default: + } + } + return nil +} + +func runHistory2(trace bool, blockNum, txNumStart uint64, hw *HistoryWrapper, ww state.StateWriter, chainConfig *params.ChainConfig, getHeader func(hash common.Hash, number uint64) *types.Header, block *types.Block, vmConfig vm.Config) (uint64, types.Receipts, error) { + header := block.Header() + vmConfig.TraceJumpDest = true + engine := ethash.NewFullFaker() + gp := new(core.GasPool).AddGas(block.GasLimit()) + usedGas := new(uint64) + var receipts types.Receipts + daoBlock := chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 + txNum := txNumStart + for i, tx := range block.Transactions() { + hw.r.SetNums(blockNum, txNum, false) + ibs := state.New(hw) + if daoBlock { + misc.ApplyDAOHardFork(ibs) + daoBlock = false + } + ibs.Prepare(tx.Hash(), block.Hash(), i) + + receipt, _, err := core.ApplyTransaction(chainConfig, getHeader, engine, nil, gp, ibs, ww, header, tx, usedGas, vmConfig, nil) + if err != nil { + return 0, nil, fmt.Errorf("could not apply tx %d [%x] failed: %w", i, tx.Hash(), err) + } + receipts = append(receipts, receipt) + txNum++ + } + + return txNum, receipts, nil +} + +// Implements StateReader and StateWriter +type HistoryWrapper struct { + r *aggregator.HistoryReader + trace bool +} + +func (hw *HistoryWrapper) ReadAccountData(address common.Address) (*accounts.Account, error) { + enc, err := hw.r.ReadAccountData(address.Bytes(), hw.trace) + if err != nil { + return nil, err + } + if len(enc) == 0 { + return nil, nil + } + var a accounts.Account + a.Reset() + pos := 0 + nonceBytes := int(enc[pos]) + pos++ + if nonceBytes > 0 { + a.Nonce = bytesToUint64(enc[pos : pos+nonceBytes]) + pos += nonceBytes + } + balanceBytes := int(enc[pos]) + pos++ + if balanceBytes > 0 { + a.Balance.SetBytes(enc[pos : pos+balanceBytes]) + pos += balanceBytes + } + codeHashBytes := int(enc[pos]) + pos++ + if codeHashBytes > 0 { + copy(a.CodeHash[:], enc[pos:pos+codeHashBytes]) + pos += codeHashBytes + } + incBytes := int(enc[pos]) + pos++ + if incBytes > 0 { + a.Incarnation = bytesToUint64(enc[pos : pos+incBytes]) + } + return &a, nil +} + +func (hw *HistoryWrapper) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) { + enc, err := hw.r.ReadAccountStorage(address.Bytes(), key.Bytes(), hw.trace) + if hw.trace { + fmt.Printf("ReadAccountStorage [%x] [%x] => [%x]\n", address, key.Bytes(), enc) + } + if err != nil { + fmt.Printf("%v\n", err) + return nil, err + } + if enc == nil { + return nil, nil + } + return enc.Bytes(), nil +} + +func (hw *HistoryWrapper) ReadAccountCode(address common.Address, incarnation uint64, codeHash common.Hash) ([]byte, error) { + return hw.r.ReadAccountCode(address.Bytes(), false /* trace */) +} + +func (hw *HistoryWrapper) ReadAccountCodeSize(address common.Address, incarnation uint64, codeHash common.Hash) (int, error) { + return hw.r.ReadAccountCodeSize(address.Bytes(), false /* trace */) +} + +func (hw *HistoryWrapper) ReadAccountIncarnation(address common.Address) (uint64, error) { + return 0, nil +} diff --git a/go.mod b/go.mod index 1a87a45689..b1ff62ea3b 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/json-iterator/go v1.1.12 github.com/julienschmidt/httprouter v1.3.0 github.com/kevinburke/go-bindata v3.21.0+incompatible - github.com/ledgerwatch/erigon-lib v0.0.0-20220211090027-9689e7046626 + github.com/ledgerwatch/erigon-lib v0.0.0-20220211234430-5f7283d0f1f1 github.com/ledgerwatch/log/v3 v3.4.0 github.com/ledgerwatch/secp256k1 v1.0.0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect diff --git a/go.sum b/go.sum index 3237beaf4b..dcc4a3b9ec 100644 --- a/go.sum +++ b/go.sum @@ -632,8 +632,8 @@ github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3P github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/ledgerwatch/erigon-lib v0.0.0-20220211090027-9689e7046626 h1:cJGqT2RxriqihCXjpLfUc98vBEoqy7HzLxKI4hD7gKA= -github.com/ledgerwatch/erigon-lib v0.0.0-20220211090027-9689e7046626/go.mod h1:NzHpr5GGDbLM/hYSU4BWB0INU6ZALzMzaqX4i03R6i0= +github.com/ledgerwatch/erigon-lib v0.0.0-20220211234430-5f7283d0f1f1 h1:VMkjKgWg5eDcB+lntInPIi8c9zdSkCu0g6ZDQBRT4FI= +github.com/ledgerwatch/erigon-lib v0.0.0-20220211234430-5f7283d0f1f1/go.mod h1:NzHpr5GGDbLM/hYSU4BWB0INU6ZALzMzaqX4i03R6i0= github.com/ledgerwatch/log/v3 v3.4.0 h1:SEIOcv5a2zkG3PmoT5jeTU9m/0nEUv0BJS5bzsjwKCI= github.com/ledgerwatch/log/v3 v3.4.0/go.mod h1:VXcz6Ssn6XEeU92dCMc39/g1F0OYAjw1Mt+dGP5DjXY= github.com/ledgerwatch/secp256k1 v1.0.0 h1:Usvz87YoTG0uePIV8woOof5cQnLXGYa162rFf3YnwaQ= -- GitLab