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] Separate Processing and State Verification on BSC #926

Merged
merged 58 commits into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3f266bf
implement the framework of fast node
Dec 2, 2021
885aeb9
implement trust protocol and verify node
keefel Jan 11, 2022
66dd9ea
testcases for getting root by diff hash
keefel Jan 20, 2022
6306002
generate diff layer by replaying block
keefel Jan 21, 2022
0b296e8
fix misc bugs of verify node
keefel Jan 25, 2022
6fffa8e
testcases for trust protocol (#742)
keefel Jan 27, 2022
359906c
implement the framework of fast node
Dec 2, 2021
c6e8652
implement trust protocol and verify node
keefel Jan 11, 2022
4905aab
testcases for getting root by diff hash
keefel Jan 20, 2022
0405b68
generate diff layer by replaying block
keefel Jan 21, 2022
529e66e
fix misc bugs of verify node
keefel Jan 25, 2022
fed2f35
testcases for trust protocol (#742)
keefel Jan 27, 2022
0ca4bc1
Merge branch 'develop' into separate-node
keefel Feb 14, 2022
1e46537
Merge pull request #763 from KeefeL/dev
unclezoro Feb 14, 2022
f7ef016
fast node verification and fix conflicts
kyrie-yl Feb 24, 2022
2ed75ab
add metrics
kyrie-yl Mar 1, 2022
7b070c0
resolve comments
kyrie-yl Mar 2, 2022
1aaab76
verify task get difflayer cache synchronously
kyrie-yl Apr 6, 2022
b978ed3
put difflayer into verifyManage cache when node restart
j75689 Apr 13, 2022
161c467
Merge branch 'develop' into fast-node-fix
j75689 Apr 13, 2022
34e8ce0
remove testing code
j75689 Apr 13, 2022
5675916
fixup! put difflayer into verifyManage cache when node restart
j75689 Apr 13, 2022
f8c6a4a
change type of diffLayerChanCache to sync.Map
j75689 Apr 19, 2022
b3a701d
refactor block remote validation code
j75689 Apr 19, 2022
be53153
rewind to last non verified block when restart fast node
j75689 Apr 19, 2022
8c6d5a8
fixup! rewind to last non verified block when restart fast node
j75689 Apr 19, 2022
1e44aa6
fixup! rewind to last non verified block when restart fast node
j75689 Apr 19, 2022
7ad4d02
Revert "change type of diffLayerChanCache to sync.Map"
j75689 Apr 20, 2022
c57fdd7
fix comments
j75689 Apr 20, 2022
e0cf707
remove unused code
j75689 Apr 20, 2022
2e6c33b
don't need to send verify task when node start
j75689 Apr 20, 2022
23913cf
remove unused code
j75689 Apr 20, 2022
a73aad6
fix validateBody
j75689 Apr 20, 2022
734d17f
fix gracefull shutdown issue
j75689 Apr 22, 2022
c840e7f
fix diffhash mismatch issue
j75689 Apr 22, 2022
3150755
fix log format
j75689 Apr 23, 2022
dfff219
fix close of closed channel issue
j75689 Apr 25, 2022
b56c19c
fix diffhash issue
j75689 Apr 26, 2022
5a254c4
add interval when getting ErrSnapshotStale
j75689 Apr 27, 2022
5f22105
add unit-test for fastnode
j75689 Apr 27, 2022
4771d86
Merge remote-tracking branch 'origin/develop' into separate-node
dean65 Apr 28, 2022
ef3ec13
fix lint error
dean65 Apr 28, 2022
7490499
setup default validator for blockchain
dean65 Apr 28, 2022
8929510
fix tests
dean65 Apr 28, 2022
e9be0d4
close verifyTask when length of verifyPeers is 0
dean65 Apr 29, 2022
0132f13
add UT tests
kyrie-yl Apr 29, 2022
2dbc8c5
Merge pull request #14 from node-real/separate-node-test
realuncle May 4, 2022
ae3bdea
fix to resolve comments
cryyl May 5, 2022
f027818
fix to resolve comments
cryyl May 5, 2022
e93cced
use NewTimer instead of time.After
dean65 May 5, 2022
4001f37
fix sorting difflayer.storage
dean65 May 5, 2022
e440880
fix TestFastNode
dean65 May 5, 2022
cc1940c
change the flag description
unclezoro May 6, 2022
84bb85c
refine the description
unclezoro May 6, 2022
73e6147
Merge remote-tracking branch 'bnb-chain/develop' into separate-node
cryyl May 6, 2022
fc08067
Merge remote-tracking branch 'bnb/develop' into separate-node
dean65 Jun 30, 2022
363bb96
fix comments
dean65 Jun 30, 2022
149718f
fix comments
dean65 Jul 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ var (
utils.NoUSBFlag,
utils.DirectBroadcastFlag,
utils.DisableSnapProtocolFlag,
utils.DisableDiffProtocolFlag,
utils.EnableTrustProtocolFlag,
utils.DiffSyncFlag,
utils.PipeCommitFlag,
utils.RangeLimitFlag,
Expand Down Expand Up @@ -98,6 +100,7 @@ var (
utils.TxPoolLifetimeFlag,
utils.TxPoolReannounceTimeFlag,
utils.SyncModeFlag,
utils.TriesVerifyModeFlag,
utils.ExitWhenSyncedFlag,
utils.GCModeFlag,
utils.SnapshotFlag,
Expand Down
76 changes: 74 additions & 2 deletions cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
Expand All @@ -29,13 +30,16 @@ import (

"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/pruner"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
Expand Down Expand Up @@ -129,6 +133,32 @@ geth snapshot verify-state <state-root>
will traverse the whole accounts and storages set based on the specified
snapshot and recalculate the root hash of state for verification.
In other words, this command does the snapshot to trie conversion.
`,
},
{
Name: "insecure-prune-all",
Usage: "Prune all trie state data except genesis block, it will break storage for fullnode, only suitable for fast node " +
"who do not need trie storage at all",
ArgsUsage: "<genesisPath>",
Action: utils.MigrateFlags(pruneAllState),
Category: "MISCELLANEOUS COMMANDS",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.AncientFlag,
utils.RopstenFlag,
utils.RinkebyFlag,
utils.GoerliFlag,
},
Description: `
will prune all historical trie state data except genesis block.
All trie nodes will be deleted from the database.

It expects the genesis file as argument.

WARNING: It's necessary to delete the trie clean cache after the pruning.
If you specify another directory for the trie clean cache via "--cache.trie.journal"
during the use of Geth, please also specify it here for correct deletion. Otherwise
the trie clean cache with default directory will be deleted.
`,
},
{
Expand Down Expand Up @@ -195,7 +225,7 @@ func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) {
}
headHeader := headBlock.Header()
//Make sure the MPT and snapshot matches before pruning, otherwise the node can not start.
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, TriesInMemory, headBlock.Root(), false, false, false)
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, TriesInMemory, headBlock.Root(), false, false, false, false)
if err != nil {
log.Error("snaptree error", "err", err)
return nil, err // The relevant snapshot(s) might not exist
Expand Down Expand Up @@ -363,6 +393,48 @@ func pruneState(ctx *cli.Context) error {
return nil
}

func pruneAllState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

genesisPath := ctx.Args().First()
if len(genesisPath) == 0 {
utils.Fatalf("Must supply path to genesis JSON file")
}
file, err := os.Open(genesisPath)
if err != nil {
utils.Fatalf("Failed to read genesis file: %v", err)
}
defer file.Close()

g := new(core.Genesis)
if err := json.NewDecoder(file).Decode(g); err != nil {
cfg := gethConfig{
Eth: ethconfig.Defaults,
Node: defaultNodeConfig(),
Metrics: metrics.DefaultConfig,
}

// Load config file.
if err := loadConfig(genesisPath, &cfg); err != nil {
utils.Fatalf("%v", err)
}
g = cfg.Eth.Genesis
}

chaindb := utils.MakeChainDatabase(ctx, stack, false, false)
pruner, err := pruner.NewAllPruner(chaindb)
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
}
if err = pruner.PruneAll(g); err != nil {
log.Error("Failed to prune state", "err", err)
return err
}
return nil
}

func verifyState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
Expand All @@ -373,7 +445,7 @@ func verifyState(ctx *cli.Context) error {
log.Error("Failed to load head block")
return errors.New("no head block")
}
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false)
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false, false)
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
Expand Down
3 changes: 3 additions & 0 deletions cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.NoUSBFlag,
utils.DirectBroadcastFlag,
utils.DisableSnapProtocolFlag,
utils.DisableDiffProtocolFlag,
utils.EnableTrustProtocolFlag,
utils.RangeLimitFlag,
utils.SmartCardDaemonPathFlag,
utils.NetworkIdFlag,
Expand All @@ -50,6 +52,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.YoloV3Flag,
utils.RopstenFlag,
utils.SyncModeFlag,
utils.TriesVerifyModeFlag,
utils.ExitWhenSyncedFlag,
utils.GCModeFlag,
utils.TxLookupLimitFlag,
Expand Down
39 changes: 38 additions & 1 deletion cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ var (
Name: "disablesnapprotocol",
Usage: "Disable snap protocol",
}
DisableDiffProtocolFlag = cli.BoolFlag{
Name: "disablediffprotocol",
Usage: "Disable diff protocol",
}
EnableTrustProtocolFlag = cli.BoolFlag{
Name: "enabletrustprotocol",
Usage: "Enable trust protocol",
}
DiffSyncFlag = cli.BoolFlag{
Name: "diffsync",
Usage: "Enable diffy sync, Please note that enable diffsync will improve the syncing speed, " +
Expand Down Expand Up @@ -264,6 +272,20 @@ var (
Usage: "The layer of tries trees that keep in memory",
Value: 128,
}
defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode
TriesVerifyModeFlag = TextMarshalerFlag{
Name: "tries-verify-mode",
Usage: `tries verify mode:
"local(default): a normal full node with complete state world(both MPT and snapshot), merkle state root will
be verified against the block header.",
"full: a fast node with only snapshot state world. Merkle state root is verified by the trustworthy remote verify node
by comparing the diffhash(an identify of difflayer generated by the block) and state root.",
"insecure: same as full mode, except that it can tolerate without verifying the diffhash when verify node does not have it.",
"none: no merkle state root verification at all, there is no need to setup or connect remote verify node at all,
it is more light comparing to full and insecure mode, but get a very small chance that the state is not consistent
with other peers."`,
Value: &defaultVerifyMode,
}
OverrideBerlinFlag = cli.Uint64Flag{
Name: "override.berlin",
Usage: "Manually specify Berlin fork-block, overriding the bundled setting",
Expand Down Expand Up @@ -1644,6 +1666,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.GlobalIsSet(DisableSnapProtocolFlag.Name) {
cfg.DisableSnapProtocol = ctx.GlobalBool(DisableSnapProtocolFlag.Name)
}
if ctx.GlobalIsSet(DisableDiffProtocolFlag.Name) {
cfg.DisableDiffProtocol = ctx.GlobalIsSet(DisableDiffProtocolFlag.Name)
}
if ctx.GlobalIsSet(EnableTrustProtocolFlag.Name) {
cfg.EnableTrustProtocol = ctx.GlobalIsSet(EnableTrustProtocolFlag.Name)
}
if ctx.GlobalIsSet(DiffSyncFlag.Name) {
cfg.DiffSync = ctx.GlobalBool(DiffSyncFlag.Name)
}
Expand Down Expand Up @@ -1677,6 +1705,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.GlobalIsSet(TriesInMemoryFlag.Name) {
cfg.TriesInMemory = ctx.GlobalUint64(TriesInMemoryFlag.Name)
}
if ctx.GlobalIsSet(TriesVerifyModeFlag.Name) {
cfg.TriesVerifyMode = *GlobalTextMarshaler(ctx, TriesVerifyModeFlag.Name).(*core.VerifyMode)
// If a node sets verify mode to full or insecure, it's a fast node and need
// to verify blocks from verify nodes, then it should enable trust protocol.
if cfg.TriesVerifyMode.NeedRemoteVerify() {
cfg.EnableTrustProtocol = true
}
}
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100
}
Expand Down Expand Up @@ -1716,7 +1752,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name)
}
if ctx.GlobalIsSet(NoDiscoverFlag.Name) {
cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{}
cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs, cfg.TrustDiscoveryURLs = []string{}, []string{}, []string{}
} else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) {
urls := ctx.GlobalString(DNSDiscoveryFlag.Name)
if urls == "" {
Expand Down Expand Up @@ -1822,6 +1858,7 @@ func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
if url := params.KnownDNSNetwork(genesis, protocol); url != "" {
cfg.EthDiscoveryURLs = []string{url}
cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs
cfg.TrustDiscoveryURLs = cfg.EthDiscoveryURLs
brilliant-lx marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
33 changes: 29 additions & 4 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,38 @@ import (

const badBlockCacheExpire = 30 * time.Second

type BlockValidatorOption func(*BlockValidator) *BlockValidator

func EnableRemoteVerifyManager(remoteValidator *remoteVerifyManager) BlockValidatorOption {
return func(bv *BlockValidator) *BlockValidator {
bv.remoteValidator = remoteValidator
return bv
brilliant-lx marked this conversation as resolved.
Show resolved Hide resolved
}
}

// BlockValidator is responsible for validating block headers, uncles and
// processed state.
//
// BlockValidator implements Validator.
type BlockValidator struct {
config *params.ChainConfig // Chain configuration options
bc *BlockChain // Canonical block chain
engine consensus.Engine // Consensus engine used for validating
config *params.ChainConfig // Chain configuration options
bc *BlockChain // Canonical block chain
engine consensus.Engine // Consensus engine used for validating
remoteValidator *remoteVerifyManager
}

// NewBlockValidator returns a new block validator which is safe for re-use
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine, opts ...BlockValidatorOption) *BlockValidator {
validator := &BlockValidator{
config: config,
engine: engine,
bc: blockchain,
}

for _, opt := range opts {
validator = opt(validator)
}

return validator
}

Expand Down Expand Up @@ -92,6 +107,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
}
return nil
},
func() error {
if v.remoteValidator != nil && !v.remoteValidator.AncestorVerified(block.Header()) {
return fmt.Errorf("%w, number: %s, hash: %s", ErrAncestorHasNotBeenVerified, block.Number(), block.Hash())
}
return nil
},
}
validateRes := make(chan error, len(validateFuns))
for _, f := range validateFuns {
Expand Down Expand Up @@ -171,6 +192,10 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return err
}

func (v *BlockValidator) RemoteVerifyManager() *remoteVerifyManager {
return v.remoteValidator
}

// CalcGasLimit computes the gas limit of the next block after parent. It aims
// to keep the baseline gas above the provided floor, and increase it towards the
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
Expand Down
Loading