以太坊同步模式源码解析

以太坊节点同步的时候支持三种模式:。速度快,重量轻,全而官方文档中已经明确--fast和--light参数选项已经被废弃那么本篇博客就带大家看一下关于此参数的源代码,深入了解同步模式的底层转变。

方法定义源代码解析

首选从源代码中找到ETH /下载/ modes.go。从文件的名字就可得知此文件是用来定义模式的,所谓的模式就是指的同步模式。下面我们看一下此文件内的所有源代码,然后再逐一分析。参考以太坊官网:www.300gu.com

package downloader

import "fmt"

// SyncMode represents the synchronisation mode of the downloader.
type SyncMode int

const (
    FullSync  SyncMode = iota // Synchronise the entire blockchain history from full blocks
    FastSync                  // Quickly download the headers, full sync only at the chain head
    LightSync                 // Download only the headers and terminate afterwards
)

func (mode SyncMode) IsValid() bool {
    return mode >= FullSync && mode <= LightSync
}

// String implements the stringer interface.
func (mode SyncMode) String() string {
    switch mode {
    case FullSync:
        return "full"
    case FastSync:
        return "fast"
    case LightSync:
        return "light"
    default:
        return "unknown"
    }
}

func (mode SyncMode) MarshalText() ([]byte, error) {
    switch mode {
    case FullSync:
        return []byte("full"), nil
    case FastSync:
        return []byte("fast"), nil
    case LightSync:
        return []byte("light"), nil
    default:
        return nil, fmt.Errorf("unknown sync mode %d", mode)
    }
}

func (mode *SyncMode) UnmarshalText(text []byte) error {
    switch string(text) {
    case "full":
        *mode = FullSync
    case "fast":
        *mode = FastSync
    case "light":
        *mode = LightSync
    default:
        return fmt.Errorf(`unknown sync mode %q, want "full", "fast" or "light"`, text)
    }
    return nil

  

同步模式类型定义

type SyncMode int

同步的类型是同步模式,而同步模式的真实类型是INT。

同步模式常量定义

const (
    FullSync  SyncMode = iota // 同步完整的区块信息
    FastSync                  // 快速同步header,然后再跟进header同步全部内容
    LightSync                 // 只下载header并在之后终止
)

 

const常量的定义给不同模式分别赋值:

- full:0

- fast:1

- light:2

串接口实现

此段代码实现了纵梁的接口,当被调用时会返回对应的字符串描述:全面,速度快,重量轻,未知此方法类似与Java的中的的toString方法。

// String implements the stringer interface.
func (mode SyncMode) String() string {
    switch mode {
    case FullSync:
        return "full"
    case FastSync:
        return "fast"
    case LightSync:
        return "light"
    default:
        return "unknown"
    }
}

  IsValid的方法

func (mode SyncMode) IsValid() bool {
    return mode >= FullSync && mode <= LightSync
}

 

此方法比较简单,当传入的模式大于等于0并且小于等于2时返回真。可以简单理解为是一个合法性的校验。

TextMarshaler方法实现

func (mode SyncMode) MarshalText() ([]byte, error) {
    switch mode {
    case FullSync:
        return []byte("full"), nil
    case FastSync:
        return []byte("fast"), nil
    case LightSync:
        return []byte("light"), nil
    default:
        return nil, fmt.Errorf("unknown sync mode %d", mode)
    }
}

  

此方法实现了编码包下的TextMarshaler接口的MarshalText方法,根据传入的同步类型值返回字符串编码(UTF-8编码的)之后的文本内容。可以简单理解为同步模式(INT)和文本内容的转换。

UnmarshalText方法实现

func (mode *SyncMode) UnmarshalText(text []byte) error {
    switch string(text) {
    case "full":
        *mode = FullSync
    case "fast":
        *mode = FastSync
    case "light":
        *mode = LightSync
    default:
        return fmt.Errorf(`unknown sync mode %q, want "full", "fast" or "light"`, text)
    }
    return nil
}

  

此方法实现了编码包下的TextUnmarshaler接口的UnmarshalText方法,根据传入的文本内容返回同步模式类型对应的值。可以简单理解为文本内容和同步模式(INT)的转换。

方法使用源代码解析

上面我们了解了同步模式的类型和方法定义,现在我们就看一下同步的过程中是怎么使用的。

默认同步模式的定义

在CMD / utils的/ flags.go文件内定义了项目启动时的基本配置参数,我们可以找到此段代码:

defaultSyncMode = eth.DefaultConfig.SyncMode
    SyncModeFlag    = TextMarshalerFlag{
        Name:  "syncmode",
        Usage: `Blockchain sync mode ("fast", "full", or "light")`,
        Value: &defaultSyncMode,
    }

  这里定义了默认的同步模式,也就是说如果不传递参数时,同步模式就是按照这里的定义来执行进一步看一下eth.DefaultConfig.SyncMode的值为多少:

var DefaultConfig = Config{
    SyncMode: downloader.FastSync,
    Ethash: ethash.Config{
        CacheDir:       "ethash",
        CachesInMem:    2,
        CachesOnDisk:   3,
        DatasetsInMem:  1,
        DatasetsOnDisk: 2,
    },
    NetworkId:     1,
    LightPeers:    100,
    DatabaseCache: 768,
    TrieCache:     256,
    TrieTimeout:   5 * time.Minute,
    GasPrice:      big.NewInt(18 * params.Shannon),

    TxPool: core.DefaultTxPoolConfig,
    GPO: gasprice.Config{
        Blocks:     20,
        Percentile: 60,
    },
}

  

大家已经看到了,默认的值为downloader.FastSync,至此已经得知如果不传递同步类型参数,GETH采用快速模式进行同步。

同步模式中途的变更

经过上面的代码分析我们是否就确定,如果不传递参数GETH一直就是通过快速模式进行同步的么?那么,再看看下面的代码分析吧。

在ETH / handler.go中方法NewProtocolManager中有这样一段代码:

// Figure out whether to allow fast sync or not
    if mode == downloader.FastSync && blockchain.CurrentBlock().NumberU64() > 0 {
        log.Warn("Blockchain not empty, fast sync disabled")
        mode = downloader.FullSync
    }
    if mode == downloader.FastSync {
        manager.fastSync = uint32(1)
    }

  这段代码是在创建ProtocolManager时进行同步模式的参数设置.blockchain.CurrentBlock()获得当前的区块信息,而NumberU64()的实现如下:

func (b *Block) NumberU64() uint64        { return b.header.Number.Uint64() }

  

也就是说NumberU64()返回的是最新区块的头部的数量。

现在整理一下这段代码的整体逻辑就是,当同步模式为快速并最新区块的高度大于0(已经同步过一部分数据)时,程序自动将同步模式转变为满,并打印警告信息。到这里,整个区块的同步模式已经豁然开朗了。

归纳总结

通过上面代付的分析,我们得到以下结论:

- geth支持三种同步模式:fast,full,light。

- 启动geth节点时,如果不传递同步模式参数,默认使用快速模式进行同步。

- 如果不传递同步模式参数或传递快,第一次启动默认使用快并且当前区块为0,因此采用快进行同步。

- 如果不传递同步模式或传递快,第二次启动默认使用快,但当前区块的头部编号不为0,程序自动将快速模式转变为完整模式。

- 因此,同步区块数据量的多少与使用全时的时机有一定关系。

 

转载于:https://www.cnblogs.com/qingpingseo/p/8875028.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值