Skip to content

Commit

Permalink
[R4R] implement State Verification && Snapshot Commit pipeline (#668)
Browse files Browse the repository at this point in the history
* pipeline commit trie

add metrics

reopen trie

* add unit testcase

* resolve keefe's comment

* resolve igor's comments

* update prefetch

remove prefetcher

* no need to return error for precacheTransaction

* fix lint issue

* add some comments

* remove useless code

* add default option is false

* fix diffsync nil point

* fix panic on  GetProofByHash

Co-authored-by: zjubfd <zjubfd@google.com>
  • Loading branch information
unclezoro and zjubfd committed Feb 17, 2022
1 parent 7435bc3 commit c9e6cee
Show file tree
Hide file tree
Showing 40 changed files with 877 additions and 403 deletions.
8 changes: 6 additions & 2 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
statedb.AddBalance(pre.Env.Coinbase, minerReward)
}
// Commit block
root, _, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber))
statedb.Finalise(chainConfig.IsEIP158(vmContext.BlockNumber))
statedb.AccountsIntermediateRoot()
root, _, err := statedb.Commit(nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Could not commit state: %v", err)
return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
Expand Down Expand Up @@ -280,7 +282,9 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB
}
}
// Commit and re-open to start with a clean state.
root, _, _ := statedb.Commit(false)
statedb.Finalise(false)
statedb.AccountsIntermediateRoot()
root, _, _ := statedb.Commit(nil)
statedb, _ = state.New(root, sdb, nil)
return statedb
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/evm/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,9 @@ func runCmd(ctx *cli.Context) error {
output, leftOverGas, stats, err := timedExec(bench, execFunc)

if ctx.GlobalBool(DumpFlag.Name) {
statedb.Commit(true)
statedb.Finalise(true)
statedb.AccountsIntermediateRoot()
statedb.Commit(nil)
statedb.IntermediateRoot(true)
fmt.Println(string(statedb.Dump(nil)))
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/evm/staterunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ func stateTestCmd(ctx *cli.Context) error {
_, s, err := test.Run(st, cfg, false)
// print state root for evmlab tracing
if ctx.GlobalBool(MachineFlag.Name) && s != nil {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", s.IntermediateRoot(false))
root := s.IntermediateRoot(false)
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", root)
}
if err != nil {
// Test failed, mark as so and dump any state to aid debugging
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ var (
utils.DirectBroadcastFlag,
utils.DisableSnapProtocolFlag,
utils.DiffSyncFlag,
utils.PipeCommitFlag,
utils.RangeLimitFlag,
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
Expand Down
7 changes: 7 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ var (
Usage: "Enable diffy sync, Please note that enable diffsync will improve the syncing speed, " +
"but will degrade the security to light client level",
}
PipeCommitFlag = cli.BoolFlag{
Name: "pipecommit",
Usage: "Enable MPT pipeline commit, it will improve syncing performance. It is an experimental feature(default is false)",
}
RangeLimitFlag = cli.BoolFlag{
Name: "rangelimit",
Usage: "Enable 5000 blocks limit for range query",
Expand Down Expand Up @@ -1634,6 +1638,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.GlobalIsSet(DiffSyncFlag.Name) {
cfg.DiffSync = ctx.GlobalBool(DiffSyncFlag.Name)
}
if ctx.GlobalIsSet(PipeCommitFlag.Name) {
cfg.PipeCommit = ctx.GlobalBool(PipeCommitFlag.Name)
}
if ctx.GlobalIsSet(RangeLimitFlag.Name) {
cfg.RangeLimit = ctx.GlobalBool(RangeLimitFlag.Name)
}
Expand Down
4 changes: 4 additions & 0 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,11 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB,
txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, []*types.Receipt, error) {
// No block rewards in PoA, so the state remains as is and uncles are dropped
var err error
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
if err != nil {
return nil, nil, err
}
header.UncleHash = types.CalcUncleHash(nil)

// Assemble and return the final block for sealing
Expand Down
29 changes: 22 additions & 7 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package core

import (
"fmt"
"time"

"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state"
Expand All @@ -26,6 +27,8 @@ import (
"github.com/ethereum/go-ethereum/trie"
)

const badBlockCacheExpire = 30 * time.Second

// BlockValidator is responsible for validating block headers, uncles and
// processed state.
//
Expand Down Expand Up @@ -54,6 +57,9 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return ErrKnownBlock
}
if v.bc.isCachedBadBlock(block) {
return ErrKnownBadBlock
}
// Header validity is known at this point, check the uncles and transactions
header := block.Header()
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
Expand Down Expand Up @@ -106,7 +112,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// transition, such as amount of used gas, the receipt roots and the state root
// itself. ValidateState returns a database batch if the validation was a success
// otherwise nil and an error is returned.
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, skipHeavyVerify bool) error {
header := block.Header()
if block.GasUsed() != usedGas {
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
Expand All @@ -125,17 +131,26 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
if receiptSha != header.ReceiptHash {
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
} else {
return nil
}
return nil
},
func() error {
}
if skipHeavyVerify {
validateFuns = append(validateFuns, func() error {
if err := statedb.WaitPipeVerification(); err != nil {
return err
}
statedb.Finalise(v.config.IsEIP158(header.Number))
statedb.AccountsIntermediateRoot()
return nil
})
} else {
validateFuns = append(validateFuns, func() error {
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
} else {
return nil
}
},
return nil
})
}
validateRes := make(chan error, len(validateFuns))
for _, f := range validateFuns {
Expand Down
Loading

0 comments on commit c9e6cee

Please sign in to comment.