erigon-pulse/cmd/state/stateless/stateless.go

530 lines
15 KiB
Go
Raw Normal View History

package stateless
import (
Merge account and storage resolvers (#504) * add_incarnation_to_acc_root_in_ih * merge cached resolver into stateful resolver * - move account root set to "post iteration" of resolver - rename "cache" to IntermediateHash * remove blockNR and bucket params from walker * fix out of range panic * calc acc.Root on the fly * remove fieldSet field from resolver, make logic of root - lazy * remove 2 parameters * working version of forward-only walk over Acc and Storage * improve test * rebase master * save progress - more tests for PrepareResolveParams, add dedicated ResolveSet for storage. Problem: See duplicates in ResolveSet hexes. Next test failing: oracle_test.go * skip old incarnations * don't rebuild when 0 requests * fix tests * start from account key when need resolve storage * Error: stateless prototype faced hashNode when extracting witness * Statless works: copy touches * Remove getAccRoot function * Remove "isAccount" parameter from resolver signature * Fix: use correct storageResolveSet in finaliseStorageRoot * Fix: when startKey changed - reset storage buffers also * Fix: if account incarnation=0 - set EmptyRoot * Fix: remove account roots by default from IntermediateHash bucket * Fix: skip abandoned storage - which appeared just after startKey * Fix: did reset acc key incorrectly * Fix: clean previous key if receive IH * Fix: IH observer - subscribe only to branch nodes (was subscribed to value nodes also) * Add DISABLE_IH and STORE_ACCOUNT_ROOT env variables for tests * Remove accNode from IH cycle * Fix flags * Fix: reset succStorage also * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: use rssStorage to HashOnly check * Fix: remove termination symbol from resolveRequest * cleanup * Fix: skip abandoned storage after IH * Debug This reverts commit 9c5eb69465f25607d546b03359b2cbcb1bd46689. * Fix linters * add_incarnation_to_acc_root_in_ih * merge cached resolver into stateful resolver * - move account root set to "post iteration" of resolver - rename "cache" to IntermediateHash * remove blockNR and bucket params from walker * fix out of range panic * calc acc.Root on the fly * remove fieldSet field from resolver, make logic of root - lazy * remove 2 parameters * working version of forward-only walk over Acc and Storage * improve test * rebase master * save progress - more tests for PrepareResolveParams, add dedicated ResolveSet for storage. Problem: See duplicates in ResolveSet hexes. Next test failing: oracle_test.go * skip old incarnations * don't rebuild when 0 requests * fix tests * start from account key when need resolve storage * Error: stateless prototype faced hashNode when extracting witness * Statless works: copy touches * Remove getAccRoot function * Remove "isAccount" parameter from resolver signature * Fix: use correct storageResolveSet in finaliseStorageRoot * Fix: when startKey changed - reset storage buffers also * Fix: if account incarnation=0 - set EmptyRoot * Fix: remove account roots by default from IntermediateHash bucket * Fix: skip abandoned storage - which appeared just after startKey * Fix: did reset acc key incorrectly * Fix: clean previous key if receive IH * Fix: IH observer - subscribe only to branch nodes (was subscribed to value nodes also) * Add DISABLE_IH and STORE_ACCOUNT_ROOT env variables for tests * Remove accNode from IH cycle * Fix flags * Fix: reset succStorage also * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: use rssStorage to HashOnly check * Fix: remove termination symbol from resolveRequest * cleanup * Fix: skip abandoned storage after IH * remove inc * remove inc from rss * tr.succStorage.Reset() * remove inc from rss * Remove hard-coding * succ.Reset * Enable CalcTrieRoots * Proper dumping of the trie * Debug * Fix for CalcTrieRoot * Fix another inteference bug * Temp * Fix test * Cleanup * remove STORE_ACCOUNT_ROOT=true flag * Fix linter * Fix linter * Disable getnodedata by default * Fix test * Fix test Co-authored-by: Alexey Akhunov <akhounov@gmail.com>
2020-05-02 18:00:57 +00:00
"bufio"
"bytes"
"context"
"encoding/csv"
"fmt"
"io/ioutil"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
chart "github.com/wcharczuk/go-chart"
"github.com/wcharczuk/go-chart/drawing"
"github.com/ledgerwatch/turbo-geth/common"
"github.com/ledgerwatch/turbo-geth/consensus/ethash"
"github.com/ledgerwatch/turbo-geth/consensus/misc"
"github.com/ledgerwatch/turbo-geth/core"
"github.com/ledgerwatch/turbo-geth/core/state"
"github.com/ledgerwatch/turbo-geth/core/types"
"github.com/ledgerwatch/turbo-geth/core/vm"
"github.com/ledgerwatch/turbo-geth/ethdb"
"github.com/ledgerwatch/turbo-geth/params"
"github.com/ledgerwatch/turbo-geth/turbo/trie"
"github.com/ledgerwatch/turbo-geth/visual"
)
var chartColors = []drawing.Color{
chart.ColorBlack,
chart.ColorRed,
chart.ColorBlue,
chart.ColorYellow,
chart.ColorOrange,
chart.ColorGreen,
}
func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWriter state.StateWriter,
chainConfig *params.ChainConfig, bcb core.ChainContext, block *types.Block,
) (types.Receipts, error) {
header := block.Header()
vmConfig := vm.Config{TraceJumpDest: true}
engine := ethash.NewFullFaker()
gp := new(core.GasPool).AddGas(block.GasLimit())
usedGas := new(uint64)
var receipts types.Receipts
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(ibs)
}
for i, tx := range block.Transactions() {
ibs.Prepare(tx.Hash(), block.Hash(), i)
receipt, err := core.ApplyTransaction(chainConfig, bcb, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig)
if err != nil {
return nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
}
receipts = append(receipts, receipt)
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, block.Transactions(), block.Uncles(), receipts); err != nil {
return nil, fmt.Errorf("finalize of block %d failed: %v", block.NumberU64(), err)
}
ctx := chainConfig.WithEIPsFlags(context.Background(), header.Number)
if err := ibs.CommitBlock(ctx, blockWriter); err != nil {
return nil, fmt.Errorf("committing block %d failed: %v", block.NumberU64(), err)
}
return receipts, nil
}
func statePicture(t *trie.Trie, number uint64) error {
filename := fmt.Sprintf("state_%d.dot", number)
f, err := os.Create(filename)
if err != nil {
return err
}
indexColors := visual.HexIndexColors
fontColors := visual.HexFontColors
visual.StartGraph(f, false)
trie.Visual(t, f, &trie.VisualOpts{
Highlights: nil,
IndexColors: indexColors,
FontColors: fontColors,
Values: true,
CutTerminals: 0,
CodeCompressed: false,
ValCompressed: false,
ValHex: true,
})
visual.EndGraph(f)
if err := f.Close(); err != nil {
return err
}
return nil
}
func parseStarkBlockFile(starkBlocksFile string) (map[uint64]struct{}, error) {
dat, err := ioutil.ReadFile(starkBlocksFile)
if err != nil {
return nil, err
}
blockStrs := strings.Split(string(dat), "\n")
m := make(map[uint64]struct{})
for _, blockStr := range blockStrs {
if len(blockStr) == 0 {
continue
}
if b, err1 := strconv.ParseUint(blockStr, 10, 64); err1 == nil {
m[b] = struct{}{}
} else {
return nil, err1
}
}
return m, nil
}
func starkData(witness *trie.Witness, starkStatsBase string, blockNum uint64) error {
filename := fmt.Sprintf("%s_%d.txt", starkStatsBase, blockNum)
f, err := os.Create(filename)
if err != nil {
return err
}
if err = trie.StarkStats(witness, f, false); err != nil {
return err
}
return nil
}
type CreateDbFunc func(string) (*ethdb.ObjectDatabase, error)
func Stateless(
ctx context.Context,
blockNum uint64,
blockSourceURI string,
statefile string,
triesize uint32,
tryPreRoot bool,
interval uint64,
ignoreOlderThan uint64,
witnessThreshold uint64,
2019-11-21 14:09:21 +00:00
statsfile string,
verifySnapshot bool,
binary bool,
createDb CreateDbFunc,
starkBlocksFile string,
starkStatsBase string,
useStatelessResolver bool,
witnessDatabasePath string,
writeHistory bool,
) {
state.MaxTrieCacheSize = uint64(triesize)
startTime := time.Now()
sigs := make(chan os.Signal, 1)
interruptCh := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
interruptCh <- true
}()
Merge account and storage resolvers (#504) * add_incarnation_to_acc_root_in_ih * merge cached resolver into stateful resolver * - move account root set to "post iteration" of resolver - rename "cache" to IntermediateHash * remove blockNR and bucket params from walker * fix out of range panic * calc acc.Root on the fly * remove fieldSet field from resolver, make logic of root - lazy * remove 2 parameters * working version of forward-only walk over Acc and Storage * improve test * rebase master * save progress - more tests for PrepareResolveParams, add dedicated ResolveSet for storage. Problem: See duplicates in ResolveSet hexes. Next test failing: oracle_test.go * skip old incarnations * don't rebuild when 0 requests * fix tests * start from account key when need resolve storage * Error: stateless prototype faced hashNode when extracting witness * Statless works: copy touches * Remove getAccRoot function * Remove "isAccount" parameter from resolver signature * Fix: use correct storageResolveSet in finaliseStorageRoot * Fix: when startKey changed - reset storage buffers also * Fix: if account incarnation=0 - set EmptyRoot * Fix: remove account roots by default from IntermediateHash bucket * Fix: skip abandoned storage - which appeared just after startKey * Fix: did reset acc key incorrectly * Fix: clean previous key if receive IH * Fix: IH observer - subscribe only to branch nodes (was subscribed to value nodes also) * Add DISABLE_IH and STORE_ACCOUNT_ROOT env variables for tests * Remove accNode from IH cycle * Fix flags * Fix: reset succStorage also * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: use rssStorage to HashOnly check * Fix: remove termination symbol from resolveRequest * cleanup * Fix: skip abandoned storage after IH * Debug This reverts commit 9c5eb69465f25607d546b03359b2cbcb1bd46689. * Fix linters * add_incarnation_to_acc_root_in_ih * merge cached resolver into stateful resolver * - move account root set to "post iteration" of resolver - rename "cache" to IntermediateHash * remove blockNR and bucket params from walker * fix out of range panic * calc acc.Root on the fly * remove fieldSet field from resolver, make logic of root - lazy * remove 2 parameters * working version of forward-only walk over Acc and Storage * improve test * rebase master * save progress - more tests for PrepareResolveParams, add dedicated ResolveSet for storage. Problem: See duplicates in ResolveSet hexes. Next test failing: oracle_test.go * skip old incarnations * don't rebuild when 0 requests * fix tests * start from account key when need resolve storage * Error: stateless prototype faced hashNode when extracting witness * Statless works: copy touches * Remove getAccRoot function * Remove "isAccount" parameter from resolver signature * Fix: use correct storageResolveSet in finaliseStorageRoot * Fix: when startKey changed - reset storage buffers also * Fix: if account incarnation=0 - set EmptyRoot * Fix: remove account roots by default from IntermediateHash bucket * Fix: skip abandoned storage - which appeared just after startKey * Fix: did reset acc key incorrectly * Fix: clean previous key if receive IH * Fix: IH observer - subscribe only to branch nodes (was subscribed to value nodes also) * Add DISABLE_IH and STORE_ACCOUNT_ROOT env variables for tests * Remove accNode from IH cycle * Fix flags * Fix: reset succStorage also * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: use rssStorage to HashOnly check * Fix: remove termination symbol from resolveRequest * cleanup * Fix: skip abandoned storage after IH * remove inc * remove inc from rss * tr.succStorage.Reset() * remove inc from rss * Remove hard-coding * succ.Reset * Enable CalcTrieRoots * Proper dumping of the trie * Debug * Fix for CalcTrieRoot * Fix another inteference bug * Temp * Fix test * Cleanup * remove STORE_ACCOUNT_ROOT=true flag * Fix linter * Fix linter * Disable getnodedata by default * Fix test * Fix test Co-authored-by: Alexey Akhunov <akhounov@gmail.com>
2020-05-02 18:00:57 +00:00
timeFF, err := os.Create("timings.txt")
if err != nil {
panic(err)
}
Merge account and storage resolvers (#504) * add_incarnation_to_acc_root_in_ih * merge cached resolver into stateful resolver * - move account root set to "post iteration" of resolver - rename "cache" to IntermediateHash * remove blockNR and bucket params from walker * fix out of range panic * calc acc.Root on the fly * remove fieldSet field from resolver, make logic of root - lazy * remove 2 parameters * working version of forward-only walk over Acc and Storage * improve test * rebase master * save progress - more tests for PrepareResolveParams, add dedicated ResolveSet for storage. Problem: See duplicates in ResolveSet hexes. Next test failing: oracle_test.go * skip old incarnations * don't rebuild when 0 requests * fix tests * start from account key when need resolve storage * Error: stateless prototype faced hashNode when extracting witness * Statless works: copy touches * Remove getAccRoot function * Remove "isAccount" parameter from resolver signature * Fix: use correct storageResolveSet in finaliseStorageRoot * Fix: when startKey changed - reset storage buffers also * Fix: if account incarnation=0 - set EmptyRoot * Fix: remove account roots by default from IntermediateHash bucket * Fix: skip abandoned storage - which appeared just after startKey * Fix: did reset acc key incorrectly * Fix: clean previous key if receive IH * Fix: IH observer - subscribe only to branch nodes (was subscribed to value nodes also) * Add DISABLE_IH and STORE_ACCOUNT_ROOT env variables for tests * Remove accNode from IH cycle * Fix flags * Fix: reset succStorage also * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: use rssStorage to HashOnly check * Fix: remove termination symbol from resolveRequest * cleanup * Fix: skip abandoned storage after IH * Debug This reverts commit 9c5eb69465f25607d546b03359b2cbcb1bd46689. * Fix linters * add_incarnation_to_acc_root_in_ih * merge cached resolver into stateful resolver * - move account root set to "post iteration" of resolver - rename "cache" to IntermediateHash * remove blockNR and bucket params from walker * fix out of range panic * calc acc.Root on the fly * remove fieldSet field from resolver, make logic of root - lazy * remove 2 parameters * working version of forward-only walk over Acc and Storage * improve test * rebase master * save progress - more tests for PrepareResolveParams, add dedicated ResolveSet for storage. Problem: See duplicates in ResolveSet hexes. Next test failing: oracle_test.go * skip old incarnations * don't rebuild when 0 requests * fix tests * start from account key when need resolve storage * Error: stateless prototype faced hashNode when extracting witness * Statless works: copy touches * Remove getAccRoot function * Remove "isAccount" parameter from resolver signature * Fix: use correct storageResolveSet in finaliseStorageRoot * Fix: when startKey changed - reset storage buffers also * Fix: if account incarnation=0 - set EmptyRoot * Fix: remove account roots by default from IntermediateHash bucket * Fix: skip abandoned storage - which appeared just after startKey * Fix: did reset acc key incorrectly * Fix: clean previous key if receive IH * Fix: IH observer - subscribe only to branch nodes (was subscribed to value nodes also) * Add DISABLE_IH and STORE_ACCOUNT_ROOT env variables for tests * Remove accNode from IH cycle * Fix flags * Fix: reset succStorage also * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: skip IH if it has wrong incarnation * Fix: use rssStorage to HashOnly check * Fix: remove termination symbol from resolveRequest * cleanup * Fix: skip abandoned storage after IH * remove inc * remove inc from rss * tr.succStorage.Reset() * remove inc from rss * Remove hard-coding * succ.Reset * Enable CalcTrieRoots * Proper dumping of the trie * Debug * Fix for CalcTrieRoot * Fix another inteference bug * Temp * Fix test * Cleanup * remove STORE_ACCOUNT_ROOT=true flag * Fix linter * Fix linter * Disable getnodedata by default * Fix test * Fix test Co-authored-by: Alexey Akhunov <akhounov@gmail.com>
2020-05-02 18:00:57 +00:00
defer timeFF.Close()
timeF := bufio.NewWriter(timeFF)
defer timeF.Flush()
fmt.Fprintf(timeF, "blockNr,exec,resolve,stateless_exec,calc_root,mod_root\n")
2019-11-21 14:09:21 +00:00
stats, err := NewStatsFile(statsfile)
check(err)
2019-11-21 14:09:21 +00:00
defer stats.Close()
blockProvider, err := BlockProviderForURI(blockSourceURI, createDb)
check(err)
defer blockProvider.Close()
stateDb, err := createDb(statefile)
check(err)
defer stateDb.Close()
var starkBlocks map[uint64]struct{}
if starkBlocksFile != "" {
starkBlocks, err = parseStarkBlockFile(starkBlocksFile)
check(err)
}
var preRoot common.Hash
if blockNum == 1 {
_, _, _, err = core.SetupGenesisBlock(stateDb, core.DefaultGenesisBlock(), writeHistory, true /* overwrite */)
check(err)
genesisBlock, _, _, err1 := core.DefaultGenesisBlock().ToBlock(nil, writeHistory)
check(err1)
preRoot = genesisBlock.Header().Root
}
chainConfig := params.MainnetChainConfig
vmConfig := vm.Config{}
engine := ethash.NewFullFaker()
if blockNum > 1 {
if errBc := blockProvider.FastFwd(blockNum - 1); errBc != nil {
check(errBc)
}
block, errBc := blockProvider.NextBlock()
check(errBc)
fmt.Printf("Block number: %d\n", blockNum-1)
fmt.Printf("Block root hash: %x\n", block.Root())
preRoot = block.Root()
if verifySnapshot {
fmt.Println("Verifying snapshot..")
checkRoots(stateDb, preRoot, blockNum-1)
fmt.Println("Verifying snapshot... OK")
}
}
batch := stateDb.NewBatch()
2019-11-07 11:14:30 +00:00
defer func() {
2019-11-07 11:17:29 +00:00
if _, err = batch.Commit(); err != nil {
2019-11-07 11:14:30 +00:00
fmt.Printf("Failed to commit batch: %v\n", err)
}
}()
tds := state.NewTrieDbState(preRoot, batch, blockNum-1)
tds.SetResolveReads(false)
tds.SetNoHistory(!writeHistory)
interrupt := false
var blockWitness []byte
var bw *trie.Witness
processed := 0
blockProcessingStartTime := time.Now()
defer func() { fmt.Printf("stoppped at block number: %d\n", blockNum) }()
var witnessDBWriter *WitnessDBWriter
var witnessDBReader *WitnessDBReader
if useStatelessResolver && witnessDatabasePath == "" {
panic("to use stateless resolver, set the witness DB path")
}
if witnessDatabasePath != "" {
var db ethdb.Database
db, err = createDb(witnessDatabasePath)
check(err)
defer db.Close()
if useStatelessResolver {
witnessDBReader = NewWitnessDBReader(db)
fmt.Printf("Will use the stateless resolver with DB: %s\n", witnessDatabasePath)
} else {
statsFilePath := fmt.Sprintf("%v.stats.csv", witnessDatabasePath)
var file *os.File
file, err = os.OpenFile(statsFilePath, os.O_RDWR|os.O_CREATE, os.ModePerm)
check(err)
defer file.Close()
statsFileCsv := csv.NewWriter(file)
defer statsFileCsv.Flush()
witnessDBWriter, err = NewWitnessDBWriter(db, statsFileCsv)
check(err)
fmt.Printf("witnesses will be stored to a db at path: %s\n\tstats: %s\n", witnessDatabasePath, statsFilePath)
}
}
err = blockProvider.FastFwd(blockNum)
check(err)
for !interrupt {
select {
case <-ctx.Done():
panic(ctx.Err())
default:
}
trace := blockNum == 50492 // false // blockNum == 545080
tds.SetResolveReads(blockNum >= witnessThreshold)
block, err := blockProvider.NextBlock()
check(err)
if block == nil {
break
}
if block.NumberU64() != blockNum {
check(fmt.Errorf("block number mismatch (want=%v got=%v)", blockNum, block.NumberU64()))
}
execStart := time.Now()
statedb := state.New(tds)
gp := new(core.GasPool).AddGas(block.GasLimit())
usedGas := new(uint64)
header := block.Header()
tds.StartNewBuffer()
var receipts types.Receipts
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
}
for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i)
var receipt *types.Receipt
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
}
if !chainConfig.IsByzantium(header.Number) {
tds.StartNewBuffer()
}
receipts = append(receipts, receipt)
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
if _, err = engine.FinalizeAndAssemble(chainConfig, header, statedb, block.Transactions(), block.Uncles(), receipts); err != nil {
fmt.Printf("Finalize of block %d failed: %v\n", blockNum, err)
return
}
execTime1 := time.Since(execStart)
execStart = time.Now()
ctx := chainConfig.WithEIPsFlags(ctx, header.Number)
if err := statedb.FinalizeTx(ctx, tds.TrieStateWriter()); err != nil {
fmt.Printf("FinalizeTx of block %d failed: %v\n", blockNum, err)
return
}
if witnessDBReader != nil {
tds.SetBlockNr(blockNum)
err = tds.ResolveStateTrieStateless(witnessDBReader)
if err != nil {
fmt.Printf("Failed to statelessly resolve state trie: %v\n", err)
return
}
} else {
var resolveWitnesses []*trie.Witness
if resolveWitnesses, err = tds.ResolveStateTrie(witnessDBWriter != nil, false); err != nil {
fmt.Printf("Failed to resolve state trie: %v\n", err)
return
}
if len(resolveWitnesses) > 0 {
witnessDBWriter.MustUpsert(blockNum, uint32(state.MaxTrieCacheSize), resolveWitnesses)
}
}
execTime2 := time.Since(execStart)
blockWitness = nil
if blockNum >= witnessThreshold {
// Witness has to be extracted before the state trie is modified
var blockWitnessStats *trie.BlockWitnessStats
bw, err = tds.ExtractWitness(trace, binary /* is binary */)
if err != nil {
fmt.Printf("error extracting witness for block %d: %v\n", blockNum, err)
return
}
var buf bytes.Buffer
blockWitnessStats, err = bw.WriteTo(&buf)
if err != nil {
fmt.Printf("error extracting witness for block %d: %v\n", blockNum, err)
return
}
blockWitness = buf.Bytes()
err = stats.AddRow(blockNum, blockWitnessStats)
2019-11-21 14:09:21 +00:00
check(err)
}
finalRootFail := false
execStart = time.Now()
if blockNum >= witnessThreshold && blockWitness != nil { // blockWitness == nil means the extraction fails
var s *state.Stateless
var w *trie.Witness
w, err = trie.NewWitnessFromReader(bytes.NewReader(blockWitness), false)
bw.WriteDiff(w, os.Stdout)
if err != nil {
fmt.Printf("error deserializing witness for block %d: %v\n", blockNum, err)
return
}
if _, ok := starkBlocks[blockNum-1]; ok {
err = starkData(w, starkStatsBase, blockNum-1)
check(err)
}
s, err = state.NewStateless(preRoot, w, blockNum-1, trace, binary /* is binary */)
if err != nil {
fmt.Printf("Error making stateless2 for block %d: %v\n", blockNum, err)
filename := fmt.Sprintf("right_%d.txt", blockNum-1)
f, err1 := os.Create(filename)
if err1 == nil {
defer f.Close()
tds.PrintTrie(f)
}
return
}
if _, ok := starkBlocks[blockNum-1]; ok {
err = statePicture(s.GetTrie(), blockNum-1)
check(err)
}
ibs := state.New(s)
ibs.SetTrace(trace)
s.SetBlockNr(blockNum)
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 {
if err = s.CheckRoot(header.Root); err != nil {
fmt.Printf("Wrong block hash %x in block %d\n", block.Hash(), blockNum)
finalRootFail = true
}
}
}
execTime3 := time.Since(execStart)
execStart = time.Now()
var preCalculatedRoot common.Hash
if tryPreRoot {
preCalculatedRoot, err = tds.CalcTrieRoots(blockNum == 1)
if err != nil {
fmt.Printf("failed to calculate preRoot for block %d: %v\n", blockNum, err)
return
}
}
execTime4 := time.Since(execStart)
execStart = time.Now()
roots, err := tds.UpdateStateTrie()
if err != nil {
fmt.Printf("failed to calculate IntermediateRoot: %v\n", err)
return
}
execTime5 := time.Since(execStart)
if tryPreRoot && tds.LastRoot() != preCalculatedRoot {
filename := fmt.Sprintf("right_%d.txt", blockNum)
f, err1 := os.Create(filename)
if err1 == nil {
defer f.Close()
tds.PrintTrie(f)
}
fmt.Printf("block %d, preCalculatedRoot %x != lastRoot %x\n", blockNum, preCalculatedRoot, tds.LastRoot())
return
}
if finalRootFail {
filename := fmt.Sprintf("right_%d.txt", blockNum)
f, err1 := os.Create(filename)
if err1 == nil {
defer f.Close()
tds.PrintTrie(f)
}
return
}
if !chainConfig.IsByzantium(header.Number) {
for i, receipt := range receipts {
receipt.PostState = roots[i].Bytes()
}
}
nextRoot := roots[len(roots)-1]
if nextRoot != block.Root() {
fmt.Printf("Root hash does not match for block %d, expected %x, was %x\n", blockNum, block.Root(), nextRoot)
return
}
tds.SetBlockNr(blockNum)
blockWriter := tds.DbStateWriter()
err = statedb.CommitBlock(ctx, blockWriter)
if err != nil {
fmt.Printf("Committing block %d failed: %v", blockNum, err)
return
}
if writeHistory {
if err = blockWriter.WriteChangeSets(); err != nil {
fmt.Printf("Writing changesets for block %d failed: %v", blockNum, err)
return
}
if err = blockWriter.WriteHistory(); err != nil {
fmt.Printf("Writing history for block %d failed: %v", blockNum, err)
return
}
}
willSnapshot := interval > 0 && blockNum > 0 && blockNum >= ignoreOlderThan && blockNum%interval == 0
if batch.BatchSize() >= 100000 || willSnapshot {
if _, err := batch.Commit(); err != nil {
fmt.Printf("Failed to commit batch: %v\n", err)
return
}
tds.EvictTries(false)
}
if willSnapshot {
// Snapshots of the state will be written to the same directory as the state file
fmt.Printf("\nSaving snapshot at block %d, hash %x\n", blockNum, block.Root())
saveSnapshot(stateDb, fmt.Sprintf("%s_%d", statefile, blockNum), createDb)
}
preRoot = header.Root
blockNum++
processed++
if blockNum%1000 == 0 {
// overwrite terminal line, if no snapshot was made and not the first line
if blockNum > 0 && !willSnapshot {
fmt.Printf("\r")
}
secondsSinceStart := time.Since(blockProcessingStartTime) / time.Second
if secondsSinceStart < 1 {
secondsSinceStart = 1
}
blocksPerSecond := float64(processed) / float64(secondsSinceStart)
fmt.Printf("Processed %d blocks (%v blocks/sec)", blockNum, blocksPerSecond)
}
fmt.Fprintf(timeF, "%d,%d,%d,%d,%d,%d\n", blockNum,
execTime1.Nanoseconds(),
execTime2.Nanoseconds(),
execTime3.Nanoseconds(),
execTime4.Nanoseconds(),
execTime5.Nanoseconds())
// Check for interrupts
select {
case interrupt = <-interruptCh:
fmt.Println("interrupted, please wait for cleanup...")
default:
}
}
fmt.Printf("Processed %d blocks\n", blockNum)
fmt.Printf("Next time specify --block %d\n", blockNum)
fmt.Printf("Stateless client analysis took %s\n", time.Since(startTime))
}