From 33d18f376ee5ab350f63d32bbf10a050b7544b92 Mon Sep 17 00:00:00 2001 From: Igor Mandrigin Date: Sat, 18 Apr 2020 16:12:51 +0300 Subject: [PATCH] Fix hash mismatch at block 76328 (#467) --- .gitignore | 3 + cmd/state/stateless/stateless.go | 10 +-- .../stateless/stateless_block_providers.go | 80 +++++++++++++++++-- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1ee8b83022e..4a278c03ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,6 @@ profile.cov /dashboard/assets/package-lock.json **/yarn-error.log +/timings.txt +right_*.txt +root_*.txt diff --git a/cmd/state/stateless/stateless.go b/cmd/state/stateless/stateless.go index bb6260312f4..e7d241b0964 100644 --- a/cmd/state/stateless/stateless.go +++ b/cmd/state/stateless/stateless.go @@ -196,11 +196,11 @@ func Stateless( chainConfig := params.MainnetChainConfig vmConfig := vm.Config{} engine := ethash.NewFullFaker() - bcb2, err := core.NewBlockChain(stateDb, nil, chainConfig, engine, vm.Config{}, nil) - check(err) if blockNum > 1 { - block := bcb2.GetBlockByNumber(blockNum - 1) + bc, errBc := core.NewBlockChain(stateDb, nil, chainConfig, engine, vm.Config{}, nil) + check(errBc) + block := bc.GetBlockByNumber(blockNum - 1) fmt.Printf("Block number: %d\n", blockNum-1) fmt.Printf("Block root hash: %x\n", block.Root()) preRoot = block.Root() @@ -296,7 +296,7 @@ func Stateless( for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) var receipt *types.Receipt - receipt, err = core.ApplyTransaction(chainConfig, bcb2, nil, gp, statedb, tds.TrieStateWriter(), header, tx, usedGas, vmConfig) + receipt, err = core.ApplyTransaction(chainConfig, blockProvider, nil, gp, statedb, tds.TrieStateWriter(), header, tx, usedGas, vmConfig) if err != nil { fmt.Printf("tx %x failed: %v\n", tx.Hash(), err) return @@ -393,7 +393,7 @@ func Stateless( ibs := state.New(s) ibs.SetTrace(trace) s.SetBlockNr(blockNum) - if err = runBlock(ibs, s, s, chainConfig, bcb2, block); err != nil { + if err = runBlock(ibs, s, s, chainConfig, blockProvider, block); err != nil { fmt.Printf("Error running block %d through stateless2: %v\n", blockNum, err) finalRootFail = true } else if !binary { diff --git a/cmd/state/stateless/stateless_block_providers.go b/cmd/state/stateless/stateless_block_providers.go index 6d60f378037..fb435533779 100644 --- a/cmd/state/stateless/stateless_block_providers.go +++ b/cmd/state/stateless/stateless_block_providers.go @@ -2,14 +2,19 @@ package stateless import ( "compress/gzip" + "context" "fmt" "io" + "io/ioutil" "net/url" "os" "strings" + "github.com/ledgerwatch/turbo-geth/common" + "github.com/ledgerwatch/turbo-geth/consensus" "github.com/ledgerwatch/turbo-geth/consensus/ethash" "github.com/ledgerwatch/turbo-geth/core" + "github.com/ledgerwatch/turbo-geth/core/rawdb" "github.com/ledgerwatch/turbo-geth/core/types" "github.com/ledgerwatch/turbo-geth/core/vm" "github.com/ledgerwatch/turbo-geth/ethdb" @@ -23,6 +28,7 @@ const ( ) type BlockProvider interface { + core.ChainContext io.Closer FastFwd(uint64) error NextBlock() (*types.Block, error) @@ -65,9 +71,18 @@ func NewBlockProviderFromDb(path string, createDbFunc CreateDbFunc) (BlockProvid return &BlockChainBlockProvider{ bc: chain, + db: ethDb, }, nil } +func (p *BlockChainBlockProvider) Engine() consensus.Engine { + return p.bc.Engine() +} + +func (p *BlockChainBlockProvider) GetHeader(h common.Hash, i uint64) *types.Header { + return p.bc.GetHeader(h, i) +} + func (p *BlockChainBlockProvider) Close() error { p.db.Close() return nil @@ -85,8 +100,11 @@ func (p *BlockChainBlockProvider) NextBlock() (*types.Block, error) { } type ExportFileBlockProvider struct { - stream *rlp.Stream - fh io.Closer + stream *rlp.Stream + engine consensus.Engine + headersDb ethdb.Database + batch ethdb.DbWithPendingMutations + fh io.Closer } func NewBlockProviderFromExportFile(fn string) (BlockProvider, error) { @@ -103,13 +121,49 @@ func NewBlockProviderFromExportFile(fn string) (BlockProvider, error) { } } stream := rlp.NewStream(reader, 0) - return &ExportFileBlockProvider{stream, fh}, nil + engine := ethash.NewFullFaker() + // keeping all the past block headers in memory + headersDb := mustCreateTempDatabase() + return &ExportFileBlockProvider{stream, engine, headersDb, nil, fh}, nil +} + +func getTempFileName() string { + tmpfile, err := ioutil.TempFile("", "headers.bolt") + if err != nil { + panic(fmt.Errorf("failed to create a temp file: %w", err)) + } + tmpfile.Close() + fmt.Printf("creating a temp headers db @ %s\n", tmpfile.Name()) + return tmpfile.Name() +} + +func mustCreateTempDatabase() ethdb.Database { + db, err := ethdb.NewBoltDatabase(getTempFileName()) + if err != nil { + panic(fmt.Errorf("failed to create a temp db for headers: %w", err)) + } + return db } func (p *ExportFileBlockProvider) Close() error { return p.fh.Close() } +func (p *ExportFileBlockProvider) WriteHeader(h *types.Header) { + if p.batch == nil { + p.batch = p.headersDb.NewBatch() + } + + rawdb.WriteHeader(context.TODO(), p.batch, h) + + if p.batch.BatchSize() > 1000 { + if _, err := p.batch.Commit(); err != nil { + panic(fmt.Errorf("error writing headers: %w", err)) + } + p.batch = nil + } +} + func (p *ExportFileBlockProvider) FastFwd(to uint64) error { var b types.Block for { @@ -117,8 +171,11 @@ func (p *ExportFileBlockProvider) FastFwd(to uint64) error { return nil } else if err != nil { return fmt.Errorf("error fast fwd: %v", err) - } else if b.NumberU64() >= to-1 { - return nil + } else { + p.WriteHeader(b.Header()) + if b.NumberU64() >= to-1 { + return nil + } } } } @@ -130,5 +187,18 @@ func (p *ExportFileBlockProvider) NextBlock() (*types.Block, error) { } else if err != nil { return nil, fmt.Errorf("error fast fwd: %v", err) } + + p.WriteHeader(b.Header()) return &b, nil } + +func (p *ExportFileBlockProvider) Engine() consensus.Engine { + return p.engine +} + +func (p *ExportFileBlockProvider) GetHeader(h common.Hash, i uint64) *types.Header { + if p.batch != nil { + return rawdb.ReadHeader(p.batch, h, i) + } + return rawdb.ReadHeader(p.headersDb, h, i) +}