从命令行开始解析同步区块的代码

本文详细介绍了Geth客户端中的三种同步模式:fast、full及light,深入探讨了这些模式的工作原理及其应用场景。同时,文章还提供了如何从命令行配置同步模式的指导。

从命令行开始解析同步区块的代码

一.同步简介

我们都知道geth支持三种同步模式

  • fast模式:从开始到结束,获取区块的header,获取区块的body,从创始块开始校验每一个元素,需要下载所有区块数据信息。速度最慢,但是能获取到所有的历史数据。

  • full模式:获取区块的header,获取区块的body,在同步到当前块之前不处理任何事务。然后获得一个快照,此后,像full节点一样进行后面的同步操作。这种方法用得最多,目的在不要在意历史数据,将历史数据按照快照的方式,不逐一验证,沿着区块下载最近数据库中的交易,有可能丢失历史数据。此方法可能会对历史数据有部分丢失,但是不影响今后的使用。

  • light模式:仅获取当前状态。验证元素需要向full节点发起相应的请求。

二.从命令行开始解析同步区块代码

geth的main包配置函数utils.SyncModeFlag,在util包中可以看到Name和Usage参数

nodeFlags = []cli.Flag{
		utils.IdentityFlag,
		utils.UnlockedAccountFlag,
		utils.PasswordFileFlag,
		utils.BootnodesFlag,
		utils.BootnodesV4Flag,
		utils.BootnodesV5Flag,
		utils.DataDirFlag,
		utils.KeyStoreDirFlag,
		utils.NoUSBFlag,
		utils.DashboardEnabledFlag,
		utils.DashboardAddrFlag,
		utils.DashboardPortFlag,
		utils.DashboardRefreshFlag,
		utils.EthashCacheDirFlag,
		utils.EthashCachesInMemoryFlag,
		utils.EthashCachesOnDiskFlag,
		utils.EthashDatasetDirFlag,
		utils.EthashDatasetsInMemoryFlag,
		utils.EthashDatasetsOnDiskFlag,
		utils.TxPoolNoLocalsFlag,
		utils.TxPoolJournalFlag,
		utils.TxPoolRejournalFlag,
		utils.TxPoolPriceLimitFlag,
		utils.TxPoolPriceBumpFlag,
		utils.TxPoolAccountSlotsFlag,
		utils.TxPoolGlobalSlotsFlag,
		utils.TxPoolAccountQueueFlag,
		utils.TxPoolGlobalQueueFlag,
		utils.TxPoolLifetimeFlag,
		utils.FastSyncFlag,
		utils.LightModeFlag,
		utils.SyncModeFlag,
		utils.GCModeFlag,
		utils.LightServFlag,
		utils.LightPeersFlag,
		utils.LightKDFFlag,
		utils.CacheFlag,
		utils.CacheDatabaseFlag,
		utils.CacheGCFlag,
		utils.TrieCacheGenFlag,
		utils.ListenPortFlag,
		utils.MaxPeersFlag,
		utils.MaxPendingPeersFlag,
		utils.EtherbaseFlag,
		utils.GasPriceFlag,
		utils.MinerThreadsFlag,
		utils.MiningEnabledFlag,
		utils.TargetGasLimitFlag,
		utils.NATFlag,
		utils.NoDiscoverFlag,
		utils.DiscoveryV5Flag,
		utils.NetrestrictFlag,
		utils.NodeKeyFileFlag,
		utils.NodeKeyHexFlag,
		utils.DeveloperFlag,
		utils.DeveloperPeriodFlag,
		utils.TestnetFlag,
		utils.RinkebyFlag,
		utils.VMEnableDebugFlag,
		utils.NetworkIdFlag,
		utils.RPCCORSDomainFlag,
		utils.RPCVirtualHostsFlag,
		utils.EthStatsURLFlag,
		utils.MetricsEnabledFlag,
		utils.FakePoWFlag,
		utils.NoCompactionFlag,
		utils.GpoBlocksFlag,
		utils.GpoPercentileFlag,
		utils.ExtraDataFlag,
		configFileFlag,
	}

flag配置详情

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

flag相关配置的结构体类型

type TextMarshalerFlag struct {
	Name  string
	Value TextMarshaler
	Usage string
}

TextMarshalerFlag操作的成员方法

func (f TextMarshalerFlag) GetName() string {
	return f.Name
}

func (f TextMarshalerFlag) String() string {
	return fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)
}

func (f TextMarshalerFlag) Apply(set *flag.FlagSet) {
	eachName(f.Name, func(name string) {
		set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
	})
}

从全局的flag配置中返回一个TextMarshalerFlag配置标志

func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler {
	val := ctx.GlobalGeneric(name)
	if val == nil {
		return nil
	}
	return val.(textMarshalerVal).v
}

默认配置使用主网络的代码

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,
	},
}

下载模式配置的代码,本段代码存在于eth包中的config.go的config结构体内部

SyncMode  downloader.SyncMode

同步的类型是SyncMode,而SyncMode的真实类型是int。const常量的定义给不同模式分别赋值:

  • full:0

  • fast: 1

  • light: 2

      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
      )
    

整个模式的变更代码请看downloader包中的modes.go

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

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

此段代码实现了stringer的接口,当被调用时会返回对应的字符串描述:full,fast,light,unknown。此方法类似与Java中的toString方法。

func (mode SyncMode) String() string {
	switch mode {
	case FullSync:
		return "full"
	case FastSync:
		return "fast"
	case LightSync:
		return "light"
	default:
		return "unknown"
	}
}

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

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)
	}
}

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

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
}

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

在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()返回的是最新区块的头部的number

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

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

GitHub地址:

https://github.com/guoshijiang/go-ethereum-code-analysis

关注问我技术公众号,加小问,拉您入技术交流群:

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The_Web3_社区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值