Skip to content

Commit 2e0530d

Browse files
committed
fast node verification
Signed-off-by: kyrie-yl <yl.on.the.way@gmail.com>
1 parent 80fd4dd commit 2e0530d

14 files changed

Lines changed: 463 additions & 25 deletions

File tree

cmd/geth/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ var (
7171
utils.NoUSBFlag,
7272
utils.DirectBroadcastFlag,
7373
utils.DisableSnapProtocolFlag,
74+
utils.DisableDiffProtocolFlag,
75+
utils.EnableTrustProtocolFlag,
7476
utils.DiffSyncFlag,
7577
utils.RangeLimitFlag,
7678
utils.USBFlag,
@@ -97,6 +99,7 @@ var (
9799
utils.TxPoolLifetimeFlag,
98100
utils.TxPoolReannounceTimeFlag,
99101
utils.SyncModeFlag,
102+
utils.TriesVerifyModeFlag,
100103
utils.ExitWhenSyncedFlag,
101104
utils.GCModeFlag,
102105
utils.SnapshotFlag,
@@ -114,7 +117,6 @@ var (
114117
utils.WhitelistFlag,
115118
utils.BloomFilterSizeFlag,
116119
utils.TriesInMemoryFlag,
117-
utils.AllowInsecureNoTriesFlag,
118120
utils.CacheFlag,
119121
utils.CacheDatabaseFlag,
120122
utils.CacheTrieFlag,

cmd/geth/usage.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{
4141
utils.NoUSBFlag,
4242
utils.DirectBroadcastFlag,
4343
utils.DisableSnapProtocolFlag,
44+
utils.DisableDiffProtocolFlag,
45+
utils.EnableTrustProtocolFlag,
4446
utils.RangeLimitFlag,
4547
utils.SmartCardDaemonPathFlag,
4648
utils.NetworkIdFlag,
@@ -50,6 +52,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
5052
utils.YoloV3Flag,
5153
utils.RopstenFlag,
5254
utils.SyncModeFlag,
55+
utils.TriesVerifyModeFlag,
5356
utils.ExitWhenSyncedFlag,
5457
utils.GCModeFlag,
5558
utils.TxLookupLimitFlag,

cmd/utils/flags.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ var (
121121
Name: "disablesnapprotocol",
122122
Usage: "Disable snap protocol",
123123
}
124+
DisableDiffProtocolFlag = cli.BoolFlag{
125+
Name: "disablediffprotocol",
126+
Usage: "Disable diff protocol",
127+
}
128+
EnableTrustProtocolFlag = cli.BoolFlag{
129+
Name: "enabletrustprotocol",
130+
Usage: "Enable trust protocol",
131+
}
124132
DiffSyncFlag = cli.BoolFlag{
125133
Name: "diffsync",
126134
Usage: "Enable diffy sync, Please note that enable diffsync will improve the syncing speed, " +
@@ -259,9 +267,11 @@ var (
259267
Usage: "The layer of tries trees that keep in memory",
260268
Value: 128,
261269
}
262-
AllowInsecureNoTriesFlag = cli.BoolTFlag{
263-
Name: "allow-insecure-no-tries",
264-
Usage: `Disable the tries state root verification, the state consistency is no longer 100% guaranteed, diffsync is not allowed if enabled. Do not enable it unless you know exactly what the consequence it will cause.`,
270+
defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode
271+
TriesVerifyModeFlag = TextMarshalerFlag{
272+
Name: "tries-verify-mode",
273+
Usage: `tries verify mode: "local", "full", "light", "insecure"`,
274+
Value: &defaultVerifyMode,
265275
}
266276
OverrideBerlinFlag = cli.Uint64Flag{
267277
Name: "override.berlin",
@@ -1622,6 +1632,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
16221632
if ctx.GlobalIsSet(DisableSnapProtocolFlag.Name) {
16231633
cfg.DisableSnapProtocol = ctx.GlobalBool(DisableSnapProtocolFlag.Name)
16241634
}
1635+
if ctx.GlobalIsSet(DisableDiffProtocolFlag.Name) {
1636+
cfg.DisableDiffProtocol = ctx.GlobalIsSet(DisableDiffProtocolFlag.Name)
1637+
}
1638+
if ctx.GlobalIsSet(EnableTrustProtocolFlag.Name) {
1639+
cfg.EnableTrustProtocol = ctx.GlobalIsSet(EnableTrustProtocolFlag.Name)
1640+
}
16251641
if ctx.GlobalIsSet(DiffSyncFlag.Name) {
16261642
cfg.DiffSync = ctx.GlobalBool(DiffSyncFlag.Name)
16271643
}
@@ -1652,8 +1668,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
16521668
if ctx.GlobalIsSet(TriesInMemoryFlag.Name) {
16531669
cfg.TriesInMemory = ctx.GlobalUint64(TriesInMemoryFlag.Name)
16541670
}
1655-
if ctx.GlobalIsSet(AllowInsecureNoTriesFlag.Name) {
1656-
cfg.NoTries = ctx.GlobalBool(AllowInsecureNoTriesFlag.Name)
1671+
if ctx.GlobalIsSet(TriesVerifyModeFlag.Name) {
1672+
cfg.TriesVerifyMode = *GlobalTextMarshaler(ctx, TriesVerifyModeFlag.Name).(*core.VerifyMode)
1673+
if cfg.TriesVerifyMode == core.FullVerify || cfg.TriesVerifyMode == core.LightVerify {
1674+
cfg.EnableTrustProtocol = true
1675+
}
1676+
if cfg.TriesVerifyMode != core.LocalVerify {
1677+
cfg.DisableDiffProtocol = true
1678+
}
16571679
}
16581680
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
16591681
cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100

core/blockchain.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ type BlockChain struct {
239239
engine consensus.Engine
240240
validator Validator // Block and state validator interface
241241
processor Processor // Block transaction processor interface
242+
verifyManager *VerifyManager
242243
vmConfig vm.Config
243244

244245
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
@@ -462,6 +463,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
462463
return bc, nil
463464
}
464465

466+
func (bc *BlockChain) StartVerify(peers VerifyPeers, allowUntrustedVerify bool) {
467+
bc.verifyManager.peers = peers
468+
bc.verifyManager.allowUntrustedVerify = allowUntrustedVerify
469+
bc.verifyManager.Start()
470+
}
471+
465472
// GetVMConfig returns the block chain VM config.
466473
func (bc *BlockChain) GetVMConfig() *vm.Config {
467474
return &bc.vmConfig
@@ -1191,6 +1198,7 @@ func (bc *BlockChain) Stop() {
11911198
close(bc.quit)
11921199
bc.StopInsert()
11931200
bc.wg.Wait()
1201+
bc.verifyManager.Stop()
11941202

11951203
// Ensure that the entirety of the state snapshot is journalled to disk.
11961204
var snapBase common.Hash
@@ -2009,6 +2017,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
20092017
log.Debug("Abort during block processing")
20102018
break
20112019
}
2020+
if bc.verifyManager != nil {
2021+
for ; !bc.verifyManager.CheckAncestorVerified(block.Header()); {
2022+
log.Debug("Block ancestor has not been verified", "hash", block.Hash(), "number", block.Number())
2023+
}
2024+
}
20122025
// If the header is a banned one, straight out abort
20132026
if BadHashes[block.Hash()] {
20142027
bc.reportBlock(block, nil, ErrBlacklistedHash)
@@ -2052,6 +2065,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
20522065
lastCanon = block
20532066
continue
20542067
}
2068+
2069+
if bc.verifyManager != nil {
2070+
bc.verifyManager.NewBlockVerifyTask(block.Header())
2071+
}
20552072
// Retrieve the parent block and it's state to execute on top
20562073
start := time.Now()
20572074

@@ -3020,6 +3037,13 @@ func EnablePersistDiff(limit uint64) BlockChainOption {
30203037
}
30213038
}
30223039

3040+
func EnableVerifyManager() BlockChainOption {
3041+
return func(chain *BlockChain) *BlockChain {
3042+
chain.verifyManager = NewVerifyManager(chain)
3043+
return chain
3044+
}
3045+
}
3046+
30233047
func (bc *BlockChain) GetRootByDiffHash(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) (*types.VerifyResult, error) {
30243048
var res types.VerifyResult
30253049
res.BlockNumber = blockNumber

core/rawdb/accessors_chain.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,26 @@ func DeleteCanonicalHash(db ethdb.KeyValueWriter, number uint64) {
6464
}
6565
}
6666

67+
func ReadTrustBlockHash(db ethdb.Reader, hash common.Hash) bool {
68+
data, _ := db.Get(trustBlockHashKey(hash))
69+
if len(data) == 0 {
70+
return false
71+
}
72+
return bytes.Equal(data,[]byte{0x01})
73+
}
74+
75+
func WriteTrustBlockHash(db ethdb.KeyValueWriter, hashkey common.Hash) {
76+
if err := db.Put(trustBlockHashKey(hashkey),[]byte{0x01}); err != nil {
77+
log.Crit("Failed to store trust block hash")
78+
}
79+
}
80+
81+
func DeleteTrustBlockHash(db ethdb.KeyValueWriter, hash common.Hash) {
82+
if err := db.Delete(trustBlockHashKey(hash)); err != nil {
83+
log.Crit("Failed to delete trust block hash")
84+
}
85+
}
86+
6787
// ReadAllHashes retrieves all the hashes assigned to blocks at a certain heights,
6888
// both canonical and reorged forks included.
6989
func ReadAllHashes(db ethdb.Iteratee, number uint64) []common.Hash {

core/rawdb/schema.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ var (
9393
// difflayer database
9494
diffLayerPrefix = []byte("d") // diffLayerPrefix + hash -> diffLayer
9595

96+
// trust block database
97+
trustBlockPrefix = []byte("tb") // trustBlockPrefix + hash -> verify result
98+
9699
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
97100
configPrefix = []byte("ethereum-config-") // config prefix for the db
98101

@@ -164,6 +167,10 @@ func headerTDKey(number uint64, hash common.Hash) []byte {
164167
func headerHashKey(number uint64) []byte {
165168
return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
166169
}
170+
// trustBlockHashKey = trustBlockPrefix + hash
171+
func trustBlockHashKey(hash common.Hash) []byte {
172+
return append(append(trustBlockPrefix, hash.Bytes()...))
173+
}
167174

168175
// headerNumberKey = headerNumberPrefix + hash
169176
func headerNumberKey(hash common.Hash) []byte {

core/verify_manager.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package core
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
lru "github.com/hashicorp/golang-lru"
8+
9+
"github.com/ethereum/go-ethereum/common"
10+
"github.com/ethereum/go-ethereum/core/rawdb"
11+
"github.com/ethereum/go-ethereum/core/types"
12+
"github.com/ethereum/go-ethereum/log"
13+
)
14+
15+
const verifiedCacheSize = 256
16+
17+
type VerifyManager struct {
18+
bc *BlockChain
19+
tasks map[common.Hash]*VerifyTask
20+
peers VerifyPeers
21+
verifiedCache *lru.Cache
22+
allowUntrustedVerify bool
23+
verifyCh chan common.Hash
24+
exitCh chan struct{}
25+
}
26+
27+
func NewVerifyManager(blockchain *BlockChain) *VerifyManager {
28+
verifiedCache, _ := lru.New(verifiedCacheSize)
29+
vm := &VerifyManager{
30+
bc: blockchain,
31+
tasks: make(map[common.Hash]*VerifyTask),
32+
verifiedCache: verifiedCache,
33+
verifyCh: make(chan common.Hash),
34+
exitCh: make(chan struct{}),
35+
}
36+
return vm
37+
}
38+
39+
func (vm *VerifyManager) Start() {
40+
//read disk store to initial verified cache
41+
//load unverified blocks in a normalized chain and start a batch of verify task
42+
header := vm.bc.CurrentHeader()
43+
vm.NewBlockVerifyTask(header)
44+
go vm.mainLoop()
45+
}
46+
47+
func (vm *VerifyManager) Stop() {
48+
defer close(vm.exitCh)
49+
vm.exitCh <- struct{}{}
50+
}
51+
52+
func (vm *VerifyManager) mainLoop() {
53+
pruneTicker := time.NewTicker(time.Second)
54+
for {
55+
select {
56+
case hash := <-vm.verifyCh:
57+
vm.cacheBlockVerified(hash)
58+
rawdb.WriteTrustBlockHash(vm.bc.db, hash)
59+
delete(vm.tasks, hash)
60+
case <-pruneTicker.C:
61+
for hash, task := range vm.tasks {
62+
if vm.bc.CurrentHeader().Number.Uint64()-task.blockHeader.Number.Uint64() > 15 {
63+
task.terminalCh <- struct{}{}
64+
delete(vm.tasks, hash)
65+
}
66+
}
67+
case <-vm.exitCh:
68+
return
69+
}
70+
}
71+
}
72+
73+
func (vm *VerifyManager) NewBlockVerifyTask(header *types.Header) {
74+
for i := 0; i < 11; i++ {
75+
hash := header.Hash()
76+
diffLayer := vm.bc.GetTrustedDiffLayer(hash)
77+
//if this block has no diff, there is no need to verify it.
78+
if diffLayer == nil {
79+
continue
80+
}
81+
//if verified cache record that this block has been verified, skip.
82+
if _, ok := vm.verifiedCache.Get(hash); ok {
83+
continue
84+
}
85+
//if verified storage record that this block has been verified, skip.
86+
if rawdb.ReadTrustBlockHash(vm.bc.db, hash) {
87+
vm.cacheBlockVerified(hash)
88+
continue
89+
}
90+
//if there already has a verify task for this block, skip.
91+
if _, ok := vm.tasks[hash]; ok {
92+
continue
93+
}
94+
diffHash, err := GetTrustedDiffHash(diffLayer)
95+
if err != nil {
96+
log.Error("failed to get diff hash", "block", hash, "number", header.Number, "error:", err)
97+
}
98+
verifyTask := NewVerifyTask(diffHash, header, vm.peers, vm.bc.db, vm.verifyCh, vm.allowUntrustedVerify)
99+
vm.tasks[hash] = verifyTask
100+
header = vm.bc.GetHeaderByHash(header.ParentHash)
101+
}
102+
}
103+
104+
func (vm *VerifyManager) cacheBlockVerified(hash common.Hash) {
105+
if vm.verifiedCache.Len() >= verifiedCacheSize {
106+
vm.verifiedCache.RemoveOldest()
107+
}
108+
vm.verifiedCache.Add(hash, true)
109+
}
110+
111+
//CheckAncestorVerified function check whether head 11 of this block has been verified.
112+
//If not, the blockchain should stop to insert new block.
113+
func (vm *VerifyManager) CheckAncestorVerified(header *types.Header) bool {
114+
pHeader := header
115+
for i := 0; i < 11; i++ {
116+
pHeader = vm.bc.GetHeaderByHash(pHeader.ParentHash)
117+
}
118+
hash := pHeader.Hash()
119+
if _, ok := vm.verifiedCache.Get(hash); ok {
120+
return true
121+
} else {
122+
return rawdb.ReadTrustBlockHash(vm.bc.db, hash)
123+
}
124+
return false
125+
}
126+
127+
func (vm *VerifyManager) HandleRootResponse(vr *types.VerifyResult, pid string) error {
128+
if vt, ok := vm.tasks[vr.BlockHash]; ok {
129+
vt.messageCh <- VerifyMessage{verifyResult: vr, peerId: pid}
130+
return nil
131+
}
132+
return fmt.Errorf("")
133+
}

0 commit comments

Comments
 (0)