Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[R4R] implement State Verification && Snapshot Commit pipeline #668

Merged
merged 12 commits into from
Jan 26, 2022
8 changes: 6 additions & 2 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,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 @@ -252,7 +254,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(false, false, true)))
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/evm/staterunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ func stateTestCmd(ctx *cli.Context) error {
_, state, err := test.Run(st, cfg, false)
// print state root for evmlab tracing
if ctx.GlobalBool(MachineFlag.Name) && state != nil {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false))
root := state.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 @@ -127,6 +127,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 @@ -1632,6 +1636,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 @@ -560,7 +560,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