以太坊启动过程源码解析

启动参数

以太坊是如何启动一个网络节点的呢?

./geth --datadir "../data0" --nodekeyhex "27aa615f5fa5430845e4e97229def5f23e9525a20640cc49304f40f3b43824dc" --bootnodes $enodeid --mine --debug --metrics --syncmode="full" --gcmode=archive  --gasprice 0 --port 30303 --rpc --rpcaddr "0.0.0.0" --rpcport 8545 --rpcapi "db,eth,net,web3,personal" --nat any --allow-insecure-unlock  2>>log 1>>log 0>>log >>log &

参数说明:

  • geth : 编译好的geth程序,可以起别名
  • datadir:数据库和keystore密钥的数据目录
  • nodekeyhex: 十六进制的P2P节点密钥
  • bootnodes:用于P2P发现引导的enode urls
  • mine:打开挖矿
  • debug:突出显示调用位置日志(文件名及行号)
  • metrics: 启用metrics收集和报告
  • syncmode:同步模式 ("fast","full",or "light")
  • gcmode:表示即时将内存中的数据写入到文件中,否则重启节点可能会导致区块高度归零而丢失数据
  • gasprice:挖矿接受交易的最低gas价格
  • port:网卡监听端口(默认值:30303)
  • rpc:启用HTTP-RPC服务器
  • rpcaddr:HTTP-RPC服务器接口地址(默认值:“localhost”)
  • rpcport:HTTP-RPC服务器监听端口(默认值:8545)
  • rpcapi:基于HTTP-RPC接口提供的API
  • nat: NAT端口映射机制 (any|none|upnp|pmp|extip:) (默认: “any”)
  • allow-insecure-unlock:用于解锁账户

详细的以太坊启动参数可以参考我的以太坊理论系列,里面有对参数的详细解释。

源码分析

geth位于cmd/geth/main.go文件中,入口如下:

func main() {
	if err := app.Run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr,err)
		os.Exit(1)
	}
}

image-20201012152238541

我们通过这张图可以看出来:main()并不是真正意义上的入口,在初始化完常量和变量以后,会先调用模块的init()函数,然后才是main()函数。所以初始化的工作是在init()函数里完成的。

func init() {
	// Initialize the CLI app and start Geth
	app.Action = geth
	app.HideVersion = true // we have a command to print the version
	app.Copyright = "Copyright 2013-2019 The go-ethereum Authors"
	app.Commands = []cli.Command{
    ....
    ....
    ...
  }

从这我们找到了入口函数geth:

func geth(ctx *cli.Context) error {
	if args := ctx.Args(); len(args) > 0 {
		return fmt.Errorf("invalid command: %q",args[0])
	}
	prepare(ctx)
	node := makeFullNode(ctx)
	defer node.Close()
	startNode(ctx,node)
	node.Wait()
	return nil
}

主要做了以下几件事:

  1. 准备操作内存缓存配额并设置度量系统
  2. 加载配置和注册服务
  3. 启动节点
  4. 守护当前线程

加载配置和注册服务

makeFullNode

1.加载配置

makeConfigNode

首先加载默认配置(作为主网节点启动):

cfg := gethConfig{
		Eth:  eth.DefaultConfig,Shh:  whisper.DefaultConfig,Node: defaultNodeConfig(),}
  • eth.DefaultConfig : 以太坊节点的主要参数配置。主要包括: 同步模式(fast)、chainid、交易池配置、gasprice、挖矿配置等;
  • whisper.DefaultConfig : 主要用于配置网络间通讯;
  • defaultNodeConfig() : 主要用于配置对外提供的RPC节点服务;
  • dashboard.DefaultConfig : 主要用于对外提供看板数据访问服务。

接着加载自定义配置(适用私有链):

if file := ctx.GlobalString(configFileFlag.Name); file != "" {
    if err := loadConfig(file,&cfg); err != nil {
        utils.Fatalf("%v",err)
    }
}

最后加载命令窗口参数(开发阶段):

utils.SetNodeConfig(ctx,&cfg.Node) // 本地节点配置
utils.SetEthConfig(ctx,stack,&cfg.Eth)// 以太坊配置
utils.SetShhConfig(ctx,&cfg.Shh)// whisper配置

2.RegisterEthService

func RegisterEthService(stack *node.Node,cfg *eth.Config) {
	var err error
	if cfg.SyncMode == downloader.LightSync {
		err = stack.Register(func(ctx *node.ServiceContext) (node.Service,error) {
			return les.New(ctx,cfg)
		})
	} else {
		err = stack.Register(func(ctx *node.ServiceContext) (node.Service,error) {
			fullNode,err := eth.New(ctx,cfg)
			if fullNode != nil && cfg.LightServ > 0 {
				ls,_ := les.NewLesServer(fullNode,cfg)
				fullNode.AddLesServer(ls)
			}
			return fullNode,err
		})
	}
	if err != nil {
		Fatalf("Failed to register the Ethereum service: %v",err)
	}
}

出现了两个新类型:ServiceContext和Service。

先看一下ServiceContext的定义:

type ServiceContext struct {
	config         *Config
	services       map[reflect.Type]Service // Index of the already constructed services
	EventMux       *event.TypeMux           // Event multiplexer used for decoupled notifications
	AccountManager *accounts.Manager        // Account manager created by the node.
}

ServiceContext主要是存储了一些从结点(或者叫协议栈)那里继承过来的、和具体Service无关的一些信息,比如结点config、account manager等。其中有一个services字段保存了当前正在运行的所有Service.

接下来看一下Service的定义:

type Service interface {
	// Protocols retrieves the P2P protocols the service wishes to start.
	// 协议检索服务希望启动的P2P协议
	Protocols() []p2p.Protocol

	// APIs retrieves the list of RPC descriptors the service provides
	// API检索服务提供的RPC描述符列表
	APIs() []rpc.API

	// Start is called after all services have been constructed and the networking
	// layer was also initialized to spawn any goroutines required by the service.
	//在所有服务都已构建完毕并且网络层也已初始化以生成服务所需的所有goroutine之后,将调用start。
	Start(server *p2p.Server) error

	// Stop terminates all goroutines belonging to the service,blocking until they
	// are all terminated.
	//Stop终止属于该服务的所有goroutine,直到它们全部终止为止一直阻塞。
	Stop() error
}

在服务注册过程中,主要注册四个服务:EthService、DashboardService、ShhService、EthStatsService,这四种服务类均扩展自Service接口。其中,EthService根据同步模式的不同,分为两种实现:

  • LightEthereum,支持LightSync模式
  • Ethereum,支持FullSync、FastSync模式

LightEthereum作为轻客户端,与Ethereum区别在于,它只需要更新区块头。当需要查询区块体数据时,需要通过调用其他全节点的les服务进行查询;另外,轻客户端本身是不能进行挖矿的。

回到RegisterEthService代码,分两个来讲:

LightSync同步:

err = stack.Register(func(ctx *node.ServiceContext) (node.Service,error) {
        return les.New(ctx,cfg)
    })
func New(ctx *node.ServiceContext,config *eth.Config) (*LightEthereum,error) {
  
  1.ctx.OpenDatabase // 创建leveldb数据库
  2.core.SetupGenesisBlockWithOverride// 根据创世配置初始化链数据目录
  3.实例化本地链id、共识引擎、注册peer节点、帐户管理器以及布隆过滤器的初始化
  4.light.NewLightChain// 使用数据库中可用的信息返回完全初始化的轻链。它初始化默认的以太坊头
  5.light.NewTxPool // 实例化交易池NewTxPool
  6.leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(),leth,nil} 
  
}

FullSync/Fast同步:

  1. 参数校验

    if config.SyncMode == downloader.LightSync {
      ....
    if !config.SyncMode.IsValid() {
      ....
    if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 {
      ....
    if config.NoPruning && config.TrieDirtyCache > 0 {  
    
  2. 打开数据库

    ctx.OpenDatabaseWithFreezer
    
  3. 根据创世配置初始化链数据目录

    core.SetupGenesisBlockWithOverride
    
  4. 实例化Ethereum对象

  5. 创建BlockChain实例对象

    core.NewBlockChain
    
  6. 实例化交易池

    core.NewTxPool
    
  7. 实例化协议管理器

    NewProtocolManager(...)
    
  8. 实例化对外API服务

    &EthAPIBackend{ctx.ExtRPCEnabled(),nil}
    

3.RegisterShhService

注册Whisper服务,用于p2p网络间加密通信。

whisper.New(cfg),nil

4.RegisterEthStatsService

注册状态推送服务,将当前以太坊网络状态推送至指定URL地址.

ethstats.New(url,ethServ,lesServ)

启动节点

启动本地节点以及启动所有注册的服务。

1.启动节点

startNode

1.1 stack.Start()

  1. 实例化p2p.Server对象。

    running := &p2p.Server{Config: n.serverConfig}
    
  2. 为注册的服务创建上下文

    for _,constructor := range n.serviceFuncs {
      ctx := &ServiceContext{
        ....
      }
    }
    
  3. 收集协议并启动新组装的p2p server

    for kind,service := range services {
      if err := service.Start(running); err != nil {
        ...
      }
    }
    
  4. 最后启动配置的RPC接口

    n.startRPC(services)
    
    • startInProc (启动进程内通讯服务)
    • startIPC (启动IPC RPC端点)
    • startHTTP(启动HTTP RPC端点)
    • startWS (启动websocket RPC端点)

2.解锁账户

unlockAccounts

在datadir/keystore目录主要用于记录在当前节点创建的帐户keystore文件。如果你的keystore文件不在本地是无法进行解锁的。

//解锁datadir/keystore目录中帐户
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
	passwords := utils.MakePasswordList(ctx)
	for i,account := range unlocks {
		unlockAccount(ks,account,i,passwords)
	}

3.注册钱包事件

events := make(chan accounts.WalletEvent,16)
stack.AccountManager().Subscribe(events)

4.监听钱包事件

	for event := range events {
			switch event.Kind {
			case accounts.WalletArrived:
				if err := event.Wallet.Open(""); err != nil {
					log.Warn("New wallet appeared,failed to open","url",event.Wallet.URL(),"err",err)
				}
			case accounts.WalletOpened:
				status,_ := event.Wallet.Status()
				log.Info("New wallet appeared","status",status)

				var derivationPaths []accounts.DerivationPath
				if event.Wallet.URL().Scheme == "ledger" {
					derivationPaths = append(derivationPaths,accounts.LegacyLedgerBaseDerivationPath)
				}
				derivationPaths = append(derivationPaths,accounts.DefaultBaseDerivationPath)

				event.Wallet.SelfDerive(derivationPaths,ethClient)

			case accounts.WalletDropped:
				log.Info("Old wallet dropped",event.Wallet.URL())
				event.Wallet.Close()
			}
		}
	}()

5.启动挖矿

ethereum.StartMining(threads)

启动守护线程

stop通道阻塞当前线程,直到节点被停止。

node.Wait()

总结

以太坊启动主要就做了3件事,包括加载配置注册服务、启动节点相关服务以及启动守护线程。

参考:github地址

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读903次。文章主要介绍了收益聚合器Beefy协议在币安智能链测试网网上的编译测试部署流程,以Pancake上的USDC-BUSD最新Curve版流动池的农场质押为例,详细介绍了完整的操作流程。_怎么在bsc网络上部署应用
文章浏览阅读952次。比特币的主要思路是,构建一个无中心、去信任的分布式记账系统。交易签名只能保证交易不是他人伪造的,却不能阻止交易的发起者自己进行多重交易,即交易的发起者将一个比特币同时转账给两个人,也就是所谓的双花。比特币应用的区块链场景也叫做公链,因为这个区块链对所有人都是公开的。除此之外,还有一种区块链应用场景,被称作联盟链。区块链的出现,使得低成本,去信任的跨组织合作成为可能,将重构组织间的关系,这个关系既包括企业间的关系,也包括政府和企业间的关系,还有政府部门间的关系。
文章浏览阅读2.5k次。虚拟人从最初的不温不火,到现在步入“出生高峰期”,元宇宙可以说是功不可没。此前,量子位发布了《虚拟数字人深度产业报告》,报告显示,到2030年我国虚拟数字人整体市场规模将达到2700亿元。其中,“身份型虚拟人”市场规模预计达到1750亿元,占主导地位,而“服务型虚拟人”总规模也将超过950亿元。得益于AI、VR/AR 等技术的发展,虚拟人的应用场景正在从传统的虚拟偶像等娱乐行业迈向更多元化的领域。_最喜欢的虚拟角色
文章浏览阅读1.3k次,点赞25次,收藏13次。通过调查和分析用户需求、兴趣和行为,你可以更好地定位你的目标受众,并在市场中找到你的定位。在设计你的Web3.0项目时,注重用户界面的友好性、交互流畅性和功能的创新性,以提供独特的用户体验。通过与有影响力的人或组织进行合作,推广你的Web3.0项目。通过与他们分享你的项目并抓住他们的推荐,可以迅速获得更多的关注度。通过优化你的网站和内容,将有助于提高你的排名,并增加有机流量。通过提供奖励激励计划,如空投、奖励机制等,激励用户参与你的Web3.0项目。的人或组织合作,可以增加你的项目的曝光度。
文章浏览阅读1.7k次。这个智能合约安全系列提供了一个广泛的列表,列出了在 Solidity 智能合约中容易反复出现的问题和漏洞。Solidity 中的安全问题可以归结为智能合约的行为方式不符合它们的意图。我们不可能对所有可能出错的事情做一个全面的列表。然而,正如传统的软件工程有常见的漏洞主题,如 SQL 注入、缓冲区超限和跨网站脚本,智能合约中也有反复出现的。_solidity安全漏洞
文章浏览阅读1.3k次。本文描述了比特币核心的编译与交互方法_编译比特币
文章浏览阅读884次。四水归堂,是中国建筑艺术中的一种独特形式。这种形式下,由四面房屋围出一个天井,房屋内侧坡向天井内倾斜,下雨时雨水会从东西南北四方流入天井,从而起到收集水源,防涝护屋的作用,寓意水聚天心,天人合一。在科技产业当中,很多时候我们需要学习古人的智慧与意蕴,尝试打通各个生态,聚四方之力为我所用,这样才能为最终用户带来最大化价值。随着数字化、智能化的发展,算力成为生产力的根基。在这一大背景下,算力需要贯通软..._超聚变csdn
文章浏览阅读1k次,点赞24次,收藏19次。云计算和区块链是当代科技领域两个备受关注的核心技术。本文将深入探讨云计算和区块链的发展历程,详细剖析其起初阶段的奠基、面临的问题、业务内容、当前研究方向、用到的技术、实际应用场景、未来发展趋势,并提供相关链接供读者深入了解。
文章浏览阅读1.5k次。融入对等网络的奥妙,了解集中式、全分布式和混合式对等网络的差异,以及区块链网络的结构与协议,让你跃入区块链的连结网络。揭开密码学的神秘面纱,探寻对称密码学、非对称密码学、哈希函数、数字签名等关键技术,让你了解信息安全的核心。解码共识算法的精髓,从理论到实践,从PoW、PoS到PBFT,让你深入了解区块链如何达成共识。探索智能合约的世界,从定义到生命周期,从执行引擎到开发与部署,带你进入无限可能的合约领域。了解令人惊叹的区块链世界,从概念到价值,从发展历程到政策法规,一篇章串联出区块链的精髓。
文章浏览阅读777次。8 月份,加密货币市场经历了明显的波动,比特币价格波动幅度较大。与此同时,NFT 市场出现大幅下跌,引发了人们对这一新兴行业未来发展趋势的担忧
文章浏览阅读8.8k次,点赞53次,收藏37次。近二十年来,我国信息科技发展日益成熟,出现的网络完全问题也是“百花齐放”。而元宇宙作为5G技术、AR/VR技术、云计算以及区块链等技术的组合体,其安全性指定会被人们所广泛关注。根据前面所讲,元宇宙融合了虚拟世界和现实世界,通过数据将现实世界的各种元素映射到数字化的虚拟世界中。所以没有数据,就等于没有元宇宙的一切;没有信息安全,元宇宙的社会生产、生活就不能正常有序地进行。所以足以可见数据安全、信息安全对元宇宙发展起到的重要作用!!_元宇宙 安全计算
文章浏览阅读1.4k次。最早使用历史 1991年采用 时间戳 追溯 数字文档,之后 2009年后创始人**中本聪** (satoshi nakamoto )日裔美国人,在设计比特币数字货币中将此理念写入应用程序中_web3.0学习
文章浏览阅读1.7k次。DeFi收益来源全面概述_drfi收益
文章浏览阅读941次,点赞17次,收藏21次。号外:教链内参1.28《从BTC现货ETF的近期数据看到的》隔夜BTC经历现货ETF通过后的情绪冷静,一度破位40k后又逐渐修复至42k上方。请珍惜42k的BTC吧。也许到下个周期,我们将不再有机会见到这个高度的BTC了。下面,让我们重温,42k的BTC,在过去四年穿越牛熊的过程中,带给我们的启迪吧。需要提醒的是,历史文字,自有历史局限性,回顾,也须带着批判性的目光阅读和审视。2021年2月8日,...
文章浏览阅读1.2k次,点赞23次,收藏21次。其实一开始我也是这么想的,但根据PoW算法机制,如果你的计算量不够大,是无法控制区块链的走向的,也就是说,即使你投入了大量的成本用于完成任务,也不能保证自己成功。例如,你持有100个币,总共持有了30天,那么,此时你的币龄就为3000,这个时候,如果你发现了一个PoS区块,那么你的币龄就会被减去一定的值,每减少365个币龄,将会从区块中获得0.05个币的利息(可理解为年利率5%),那么在这个案例中,利息=3000×5%/365=0.41个币。前面说过,谁的算力强,谁最先解决问题的概率就越大。
文章浏览阅读1.9k次。这里主要实现的部分继续下去,对 Blockchain 这个对象有一些修改,如果使用 TS 的话可能要修改对应的 interface,但是如果是 JS 的话就无所谓了。需要安装的依赖有:express现在的 express 已经不内置 body-parser,需要作为单独的依赖下载request不下载会报错,是使用 request-promise 所需要的依赖和已经 deprecated 了,具体 reference 可以参考。_js区块链
文章浏览阅读1k次,点赞19次,收藏19次。作者:Zach Pandl Grayscale编译:象牙山首席村民 碳链价值以太坊在2023年取得了丰厚的回报。但表现不如比特币以及其他一些智能合约公链代币。我们认为,这反映了今年比特币特有的积极因素以及以太坊链上活动的缓慢复苏。尽管以太坊的涨幅低于比特币,但从绝对值和风险调整值来看,今年以太坊的表现优于传统资产类别。以太坊不断增长的L2生态系统的发展可能会吸引新用户,并在2024年支撑以太币的...
文章浏览阅读908次,点赞20次,收藏20次。通证是以数字形式存在,代表的是一种权利、一种固有和内在的价值。徐教授告诉我:多年的职业经历,多年的为易货贸易的思考,认识到在处理贸易和经济领域的关系时,应以提高人民生活水平、保证社会成员充分就业、保证就业成员实际收入和有效需求的大幅稳定增长、实现世界资源的充分利用以及扩大货物的生产和交换为目的,期望通过达成互惠互利安排,实行公开、公平、公正的“三公原则”,开展国家与国家、企业与企业之间的易货贸易,规避因信用问题引起的各类风险,消除国际贸易中的歧视待遇,促进全球国家的经济发展,从而为实现上述目标做出贡献。
文章浏览阅读2.5k次。由于webase文档原因,查找起来比较局限,有时候想找一个api却又忘了在哪个模块的目录下,需要一步一步单独点,而利用文档自带的检索功能又因为查找文档全部信息,显得十分缓慢,所以整理了有关WeBASE的api列表但不可否认,现在只有列表,没有对应的页面跳转,文章目的也只是为了多了解webase的接口_webase私钥管理里获取
文章浏览阅读1.4k次,点赞28次,收藏21次。基于​openzeppelin来构建我们的NFT,并用一个例子来手把手的说明如何在opensea快速发布自己的NFT智能合约(ERC721)。