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

fast node verification #4

Open
wants to merge 4 commits into
base: separate-nodes
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
4 changes: 3 additions & 1 deletion 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,

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.

Copy link
Owner

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.

utils.EnableTrustProtocolFlag,
utils.DiffSyncFlag,
utils.RangeLimitFlag,
utils.USBFlag,
Expand All @@ -97,6 +99,7 @@ var (
utils.TxPoolLifetimeFlag,
utils.TxPoolReannounceTimeFlag,
utils.SyncModeFlag,
utils.TriesVerifyModeFlag,
utils.ExitWhenSyncedFlag,
utils.GCModeFlag,
utils.SnapshotFlag,
Expand All @@ -114,7 +117,6 @@ var (
utils.WhitelistFlag,
utils.BloomFilterSizeFlag,
utils.TriesInMemoryFlag,
utils.AllowInsecureNoTriesFlag,
utils.CacheFlag,
utils.CacheDatabaseFlag,
utils.CacheTrieFlag,
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
36 changes: 31 additions & 5 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,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 @@ -259,9 +267,11 @@ var (
Usage: "The layer of tries trees that keep in memory",
Value: 128,
}
AllowInsecureNoTriesFlag = cli.BoolTFlag{
Name: "allow-insecure-no-tries",
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",

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

Usage: `tries verify mode: "local", "full", "insecure", "none"`,
Value: &defaultVerifyMode,
}
OverrideBerlinFlag = cli.Uint64Flag{
Name: "override.berlin",
Expand Down Expand Up @@ -1622,6 +1632,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 @@ -1652,8 +1668,18 @@ 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(AllowInsecureNoTriesFlag.Name) {
cfg.NoTries = ctx.GlobalBool(AllowInsecureNoTriesFlag.Name)
if ctx.GlobalIsSet(TriesVerifyModeFlag.Name) {
cfg.TriesVerifyMode = *GlobalTextMarshaler(ctx, TriesVerifyModeFlag.Name).(*core.VerifyMode)
// If a node sets verify mode to full or light, 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 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 {

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.

cfg.DisableDiffProtocol = true
}
}
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100
Expand Down
41 changes: 40 additions & 1 deletion core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,26 @@ type BlockValidator struct {
config *params.ChainConfig // Chain configuration options
bc *BlockChain // Canonical block chain
engine consensus.Engine // Consensus engine used for validating
remoteValidator *VerifyManager
}

// 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, mode *VerifyMode) *BlockValidator {
validator := &BlockValidator{
config: config,
engine: engine,
bc: blockchain,
}
if mode.NeedRemoteVerify() {
validator.remoteValidator = NewVerifyManager(blockchain, *mode == InsecureVerify)
}
return validator
}

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

// ValidateBody validates the given block's uncles and verifies the block
// header's transaction and uncle roots. The headers are assumed to be already
// validated at this point.
Expand Down Expand Up @@ -149,6 +157,37 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return err
}

func (v *BlockValidator) StartRemoteVerify(peers VerifyPeers) {
v.remoteValidator.peers = peers
if v.remoteValidator != nil {
go v.remoteValidator.verifyManagerLoop()
}
}

func (v * BlockValidator) StopRemoteVerify() {
if v.remoteValidator != nil {
v.remoteValidator.Stop()
}
}

func (v * BlockValidator) VerifyBlock(header *types.Header) {
if v.remoteValidator != nil {
v.remoteValidator.newTaskCh <- header
}
}

// ValidateBlockVerify validate that weather the H-11 ancestor of the block has been verified by peers.
// If not, the blockchain should halt.
func (v * BlockValidator) ValidateBlockVerify(block *types.Block) error {
if v.remoteValidator != nil {
header := block.Header()
if !v.remoteValidator.AncestorVerified(v.bc.GetHeaderByNumber(header.Number.Uint64())) {
return fmt.Errorf("block's ancessor %x has not been verified", block.Hash())
}
}
return nil
}

// 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
20 changes: 17 additions & 3 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
diffNumToBlockHashes: make(map[uint64]map[common.Hash]struct{}),
diffPeersToDiffHashes: make(map[string]map[common.Hash]struct{}),
}
bc.validator = NewBlockValidator(chainConfig, bc, engine)
bc.processor = NewStateProcessor(chainConfig, bc, engine)

var err error
Expand Down Expand Up @@ -1191,6 +1190,7 @@ func (bc *BlockChain) Stop() {
close(bc.quit)
bc.StopInsert()
bc.wg.Wait()
bc.validator.StopRemoteVerify()

// Ensure that the entirety of the state snapshot is journalled to disk.
var snapBase common.Hash
Expand Down Expand Up @@ -2122,6 +2122,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
blockWriteTimer.Update(time.Since(substart))
blockInsertTimer.UpdateSince(start)

//Start a routine to verify this block.
bc.validator.VerifyBlock(block.Header())

switch status {
case CanonStatTy:
log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(),
Expand Down Expand Up @@ -3020,8 +3023,15 @@ func EnablePersistDiff(limit uint64) BlockChainOption {
}
}

func (bc *BlockChain) GetRootByDiffHash(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) (*types.VerifyResult, error) {
var res types.VerifyResult
func EnableBlockValidator(chainConfig *params.ChainConfig, engine consensus.Engine, mode *VerifyMode) BlockChainOption {
return func(bc *BlockChain) *BlockChain {
bc.validator = NewBlockValidator(chainConfig, bc, engine, mode)
return bc
}
}

func (bc *BlockChain) GetRootByDiffHash(blockNumber uint64, blockHash common.Hash, diffHash common.Hash) (*VerifyResult, error) {
var res VerifyResult
res.BlockNumber = blockNumber
res.BlockHash = blockHash

Expand Down Expand Up @@ -3076,6 +3086,10 @@ func (bc *BlockChain) GetRootByDiffHash(blockNumber uint64, blockHash common.Has
return &res, nil
}

func (bc *BlockChain) GenerateDiffLayer(blockHash common.Hash) (*types.DiffLayer, error) {
return &types.DiffLayer{}, nil
}

func (bc *BlockChain) GetTrustedDiffLayer(blockHash common.Hash) *types.DiffLayer {
var diff *types.DiffLayer
if cached, ok := bc.diffLayerCache.Get(blockHash); ok {
Expand Down
6 changes: 5 additions & 1 deletion core/blockchain_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ func (it *insertIterator) next() (*types.Block, error) {
return it.chain[it.index], it.errors[it.index]
}
// Block header valid, run body validation and return
return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index])
if err := it.validator.ValidateBody(it.chain[it.index]); err != nil {
return it.chain[it.index], err
}
// Block body valid, run remote verify and return
return it.chain[it.index], it.validator.ValidateBlockVerify(it.chain[it.index])
}

// peek returns the next block in the iterator, along with any potential validation
Expand Down
20 changes: 20 additions & 0 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ func DeleteCanonicalHash(db ethdb.KeyValueWriter, number uint64) {
}
}

func IsTrustBlock(db ethdb.Reader, hash common.Hash) bool {
data, _ := db.Get(trustBlockHashKey(hash))
if len(data) == 0 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about:

if len(data) != 1{
   return false
}
return data[0] == byteTrue 

We can save the allocation of slices each time, more memory friendly.

return false
}
return bytes.Equal(data,[]byte{byteTrue})
}

func MarkTrustBlock(db ethdb.KeyValueWriter, hashkey common.Hash) {
if err := db.Put(trustBlockHashKey(hashkey),[]byte{byteTrue}); err != nil {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest define []byte{byteTrue} as a var

log.Crit("Failed to store trust block hash")
}
}

func DeleteTrustBlockHash(db ethdb.KeyValueWriter, hash common.Hash) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never been used, I think we should delete the storage once we are 100% sure it will not be used any longer.

if err := db.Delete(trustBlockHashKey(hash)); err != nil {
log.Crit("Failed to delete trust block hash")
}
}

// ReadAllHashes retrieves all the hashes assigned to blocks at a certain heights,
// both canonical and reorged forks included.
func ReadAllHashes(db ethdb.Iteratee, number uint64) []common.Hash {
Expand Down
9 changes: 9 additions & 0 deletions core/rawdb/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ var (
// difflayer database
diffLayerPrefix = []byte("d") // diffLayerPrefix + hash -> diffLayer

// trust block database
trustBlockPrefix = []byte("trust-block-") // trustBlockPrefix + hash -> verify result

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete useless code


preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db

Expand All @@ -118,6 +121,8 @@ const (

// freezerDifficultyTable indicates the name of the freezer total difficulty table.
freezerDifficultyTable = "diffs"
//

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete comment

byteTrue = 0x01
)

// FreezerNoSnappy configures whether compression is disabled for the ancient-tables.
Expand Down Expand Up @@ -164,6 +169,10 @@ func headerTDKey(number uint64, hash common.Hash) []byte {
func headerHashKey(number uint64) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
}
// trustBlockHashKey = trustBlockPrefix + hash
func trustBlockHashKey(hash common.Hash) []byte {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete useless code

return append(append(trustBlockPrefix, hash.Bytes()...))
}

// headerNumberKey = headerNumberPrefix + hash
func headerNumberKey(hash common.Hash) []byte {
Expand Down
Loading