-
Notifications
You must be signed in to change notification settings - Fork 2
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
fast node verification #4
base: separate-nodes
Are you sure you want to change the base?
Conversation
Signed-off-by: kyrie-yl <[email protected]>
@@ -71,6 +71,8 @@ var ( | |||
utils.NoUSBFlag, | |||
utils.DirectBroadcastFlag, | |||
utils.DisableSnapProtocolFlag, | |||
utils.DisableDiffProtocolFlag, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean it is not proper to introduce such low level flag. Especially it is related with other flags.
For example: when TriesVerifyModeFlag
need trust protocol while EnableTrustProtocolFlag
is false, it is become complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider we should disable diff protocol in verify node, and enable trust protocol, we didn't have better solution temporary.
cmd/utils/flags.go
Outdated
defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode | ||
TriesVerifyModeFlag = TextMarshalerFlag{ | ||
Name: "tries-verify-mode", | ||
Usage: `tries verify mode: "local", "full", "light", "insecure"`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please explain in details what the each mode means in the usage
so that the user can understand
core/verify_modes.go
Outdated
} | ||
|
||
func (mode *VerifyMode) NeedRemoteVerify() bool { | ||
if *mode == FullVerify || *mode == LightVerify { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return *mode == FullVerify || *mode == LightVerify
directly?
core/blockchain.go
Outdated
@@ -239,6 +239,7 @@ type BlockChain struct { | |||
engine consensus.Engine | |||
validator Validator // Block and state validator interface | |||
processor Processor // Block transaction processor interface | |||
verifyManager *VerifyManager |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we use interface here, like validator
, processor
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verifyManager
is not a good name, we need distinguish it from validator
here.
core/blockchain.go
Outdated
@@ -462,6 +463,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par | |||
return bc, nil | |||
} | |||
|
|||
func (bc *BlockChain) StartVerify(peers VerifyPeers, allowUntrustedVerify bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not pass allowUntrustedVerify
when StartVerify
, but pass it when new the verifyManager.
core/trie_verify.go
Outdated
header := vm.bc.CurrentHeader() | ||
// Start verify task from H to H-11 if need. | ||
vm.NewBlockVerifyTask(header) | ||
prune := time.NewTicker(time.Second) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prune
--> pruneTicker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 second is too short for pruneTicker
, I will suggest 5 seconds
core/trie_verify.go
Outdated
} | ||
case <-prune.C: | ||
for hash, task := range vm.tasks { | ||
if vm.bc.CurrentHeader().Number.Uint64()-task.blockHeader.Number.Uint64() > 15 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
15 is magic number here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The subtraction here may overflow.
core/trie_verify.go
Outdated
|
||
func (vm *VerifyManager) Stop() { | ||
// stop all the tasks | ||
for _, task := range vm.tasks { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
race condition on vm.tasks
, it may double close task.terminalCh
and cause panic
core/trie_verify.go
Outdated
func (vt *VerifyTask) Start(verifyCh chan common.Hash) { | ||
vt.startAt = time.Now() | ||
|
||
vt.selectPeersToVerify(defaultPeerNumber) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please try better name thanselectPeersToVerify
. 主语是select,就是挑选,实际上会把请求发出去。
core/trie_verify.go
Outdated
validPeers = append(validPeers, p) | ||
} | ||
} | ||
// if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean the code.
core/trie_verify.go
Outdated
} | ||
|
||
// if n < len(validPeers), select n peers from validPeers randomly. | ||
rand.Seed(time.Now().UnixNano()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please log(warn) if there is no node to request.
core/trie_verify.go
Outdated
func (vt *VerifyTask) compareRootHashAndWrite(msg VerifyMessage, verifyCh chan common.Hash) { | ||
if msg.verifyResult.Root == vt.blockHeader.Root { | ||
blockhash := msg.verifyResult.BlockHash | ||
rawdb.MarkTrustBlock(vt.db, blockhash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have done MarkTrustBlock
twice, I think we can delete here, but let VerifyManager to do it.
core/types.go
Outdated
// VerifyBlock verify the given blcok. | ||
VerifyBlock(header *types.Header) | ||
// ValidateBlockVerify validate the given block has been verified. | ||
ValidateBlockVerify(block *types.Block) error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ValidateBlockVerify
is too confusing...
core/types.go
Outdated
@@ -32,6 +32,17 @@ type Validator interface { | |||
// ValidateState validates the given statedb and optionally the receipts and | |||
// gas used. | |||
ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error | |||
|
|||
// StartRemoteVerify start the remote verify routine for given peers. | |||
StartRemoteVerify(peers VerifyPeers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is some way to hide StartRemoteVerify
and StopRemoteVerify
, we should expose as less interface as possible.
core/types.go
Outdated
// StopRemoteVerify stop the remote verify routine. | ||
StopRemoteVerify() | ||
// VerifyBlock verify the given blcok. | ||
VerifyBlock(header *types.Header) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can merge VerifyBlock
and ValidateBody
into one.
core/block_validator.go
Outdated
validator := &BlockValidator{ | ||
config: config, | ||
engine: engine, | ||
bc: blockchain, | ||
} | ||
if mode.NeedRemoteVerify() { | ||
remoteValidator := NewVerifyManager(blockchain, peers, *mode == InsecureVerify) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should assign validator's remoteValidator, not just a local variable.
core/block_validator.go
Outdated
if !v.remoteValidator.AncestorVerified(v.bc.GetHeaderByNumber(header.Number.Uint64())) { | ||
return fmt.Errorf("block's ancessor %x has not been verified", block.Hash()) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap these code as a new validateFunc is better? Can run concurrently with above another two validateFuncs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please run concurrently like another two validateFuncs.
core/trie_verify.go
Outdated
if diffLayer, err = vm.bc.GenerateDiffLayer(hash); err != nil { | ||
log.Error("failed to get diff layer", "block", hash, "number", header.Number, "error", err) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a case if the block is an empty block, the error is nil and difflayer is nil too. So, add another branch to test if difflayer == nil, if so, return directly.
core/trie_verify.go
Outdated
if header.TxHash == types.EmptyRootHash { | ||
parent := vm.bc.GetHeaderByHash(header.ParentHash) | ||
if header.Root == parent.Root { | ||
return true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need use if branch, actually if you use if branch, when not equal, you should use else branch to return false here, so recommend to return header.Root == parent.Root
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think when header.Root == parent.Root, we should check whether the parent has been verified, if not, this empty block is not verified, if the parent has been verified already, this empty block is verified. So maybe here should be
if header.Root != parent.Root { return false }
core/trie_verify.go
Outdated
allowUntrusted: allowUntrusted, | ||
|
||
newTaskCh: make(chan *types.Header), | ||
verifyCh: make(chan common.Hash), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will suggest verifyCh
have some buffer, like 11, so than the main process will not been blocked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So do newTaskCh
, please allocate some buffer.
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.`, | ||
defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode | ||
TriesVerifyModeFlag = TextMarshalerFlag{ | ||
Name: "tries-verify-mode", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better description is needed to let users understand the meaning of each mode
cmd/utils/flags.go
Outdated
} | ||
// If a node sets verify mode but not local, it's a fast node whose difflayer is not integral. | ||
// So fast node should disable diff protocol. | ||
if cfg.TriesVerifyMode != core.LocalVerify { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discuss with nash, we can delete flag DisableDiffProtocol
, even fast node can provide difflayer for diff sync.
core/rawdb/schema.go
Outdated
@@ -93,6 +93,9 @@ var ( | |||
// difflayer database | |||
diffLayerPrefix = []byte("d") // diffLayerPrefix + hash -> diffLayer | |||
|
|||
// trust block database | |||
trustBlockPrefix = []byte("trust-block-") // trustBlockPrefix + hash -> verify result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please delete useless code
core/rawdb/schema.go
Outdated
@@ -165,6 +168,11 @@ func headerHashKey(number uint64) []byte { | |||
return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...) | |||
} | |||
|
|||
// trustBlockHashKey = trustBlockPrefix + hash | |||
func trustBlockHashKey(hash common.Hash) []byte { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please delete useless code
core/trie_verify.go
Outdated
tryAllPeersTime = 15 * time.Second | ||
) | ||
|
||
type verifyManager struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename verifyManager
to remoteVerifyManager
core/trie_verify.go
Outdated
@@ -0,0 +1,345 @@ | |||
package core |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file name trie_verify
can rename to remote_state_verifier
core/trie_verify.go
Outdated
return nil | ||
} | ||
|
||
func (mode *VerifyMode) NeedRemoteVerify() bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change func (mode *VerifyMode) NeedRemoteVerify() bool
to func (mode VerifyMode) NeedRemoteVerify() bool
, so that you can change
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine, mode *VerifyMode, peers verifyPeers) *BlockValidator
to
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine, mode VerifyMode, peers verifyPeers) *BlockValidator {
core/block_validator.go
Outdated
@@ -149,6 +160,16 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD | |||
return err | |||
} | |||
|
|||
func (v *BlockValidator) VerifyBlockTrie(header *types.Header) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let us try subscribe the header info rather than called in main process.
core/trie_verify.go
Outdated
tasks map[common.Hash]*verifyTask | ||
peers verifyPeers | ||
verifiedCache *lru.Cache | ||
allowUntrusted bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we rename it to allowInsecure
, since the peer is still trusted, but the result is not insecure
Please add promethus metrics |
0d80e6f
to
f3820ca
Compare
Signed-off-by: kyrie-yl <[email protected]>
f3820ca
to
1af60b3
Compare
Signed-off-by: kyrie-yl <[email protected]>
No description provided.