go ethereum 源码剖析 1

创作人 Leo


编辑时间 Wed Jan 1,2020 at 10:13


consensus 共识引擎模块

go-ethereum 中 consensus 包是共识协议包,ethash 是 PoW 的协议实现

consensus/ethash/sealer.go
seal 负责对区块进行封装,计算 hash 值(也就是工作量的证明)
如果用户配置了矿工数量(threads)0或者未设置,ethash将自己决定矿工数为CPU核数对等数量,设置-1则代表不挖矿
当有矿工挖到hash,则通过 abort 通道通知其他矿工终止计算

// Seal implements consensus.Engine, attempting to find a nonce that satisfies
// the block's difficulty requirements.
func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
	// If we're running a fake PoW, simply return a 0 nonce immediately
	...
	// If we're running a shared PoW, delegate sealing to it
	...
	// Create a runner and the multiple search threads it directs
	abort := make(chan struct{})

	ethash.lock.Lock()
	threads := ethash.threads
	if ethash.rand == nil {
		seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
		if err != nil {
			ethash.lock.Unlock()
			return err
		}
		ethash.rand = rand.New(rand.NewSource(seed.Int64())) // 计算哈希种子
	}
	ethash.lock.Unlock()
	if threads == 0 {
		threads = runtime.NumCPU() // 决定矿工数量
	}
	if threads < 0 {
		threads = 0 // Allows disabling local mining without extra logic around local/remote
	}
	// Push new work to remote sealer
	if ethash.remote != nil {
		ethash.remote.workCh <- &sealTask{block: block, results: results}
	}
	var (
		pend   sync.WaitGroup // 并行多个矿工同时挖矿
		locals = make(chan *types.Block)
	)
	for i := 0; i < threads; i++ {
		pend.Add(1)
		go func(id int, nonce uint64) {
			defer pend.Done()
			ethash.mine(block, id, nonce, abort, locals) // 调用挖矿函数,矿工开始工作
		}(i, uint64(ethash.rand.Int63()))
	}
	// Wait until sealing is terminated or a nonce is found
	go func() {
		var result *types.Block
		select {
		case <-stop:
			// Outside abort, stop all miner threads
			close(abort) // 外部终止,直接发送停止挖矿信号
		case result = <-locals:
            // One of the threads found a block, abort all others
            // 有矿工找到区块,终止其他矿工
			select {
			case results <- result:
			default:
				ethash.config.Log.Warn("Sealing result is not read by miner", "mode", "local", "sealhash", ethash.SealHash(block.Header()))
			}
			close(abort)
		case <-ethash.update:
            // Thread count was changed on user request, restart
			close(abort)
			if err := ethash.Seal(chain, block, results, stop); err != nil {
				ethash.config.Log.Error("Failed to restart sealing after update", "err", err)
			}
		}
		// Wait for all miners to terminate and return the block
		pend.Wait()
	}()
	return nil
}

ethash.mine 挖矿函数,通过新的难度种子 seed 寻找新的区块头 nonce
consensus/ethash/algorithm.go 是挖矿算法实现,以太坊采用 Dagger-Hashimoto 算法:
Hashimoto:一种 IO 复杂的挖矿算法,设计初衷是对抗 ASIC 集成电路
Dagger:使用有向无环图实现的挖矿算法,Dagger算法的结果的计算为内存复杂型(memory-hard computation),而验证可以很容易通过内存验证(memory-easy validation)

Dagger-Hashimoto 算法

console 控制台交互模块

geth 通过内置JS引擎实现客户端交互,用户可以通过 模块.功能 的方式进行区块查询、转账、账号操作等一系列操作
console 包是命令行交互的具体实现,geth 的 console 初始化在 cmd/geth/consolecmd.go 文件中

consolecmd.go
localConsole 在执行 geth console 会被调用
remoteConsole 在执行 geth attach 时被调用


var (
	consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}

	consoleCommand = cli.Command{
		Action:   utils.MigrateFlags(localConsole),
		Name:     "console",
		...
	}

	attachCommand = cli.Command{
		Action:    utils.MigrateFlags(remoteConsole),
		Name:      "attach",
		...
	}

	...
)

// localConsole starts a new geth node, attaching a JavaScript console to it at the
// same time.
func localConsole(ctx *cli.Context) error {
	// Create and start the node based on the CLI flags
	prepare(ctx)
	node := makeFullNode(ctx)
	startNode(ctx, node)
	defer node.Close()

	// Attach to the newly started node and start the JavaScript console
	client, err := node.Attach()
	if err != nil {
		utils.Fatalf("Failed to attach to the inproc geth: %v", err)
	}
	config := console.Config{
		DataDir: utils.MakeDataDir(ctx),
		DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
		Client:  client,
		Preload: utils.MakeConsolePreloads(ctx),
	}

    // 初始化交互命令行
	console, err := console.New(config)
	if err != nil {
		utils.Fatalf("Failed to start the JavaScript console: %v", err)
	}
	defer console.Stop(false)

	// If only a short execution was requested, evaluate and return
	if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
		console.Evaluate(script)
		return nil
	}
	// Otherwise print the welcome screen and enter interactive mode
    console.Welcome()
    
    // 开始交互
	console.Interactive()

	return nil
}

// remoteConsole will connect to a remote geth instance, attaching a JavaScript
// console to it.
func remoteConsole(ctx *cli.Context) error {
	...
}

golang JS 语法解析&交互开源库 otto

asm

core/asm 内嵌汇编,操作字节码
智能合约载入EVM之前会经过这个模块的处理

bloombits

core/bloombits
布隆过滤器的实现
布隆算法:首先创建bitmap结构,通过将元素的哈希值拆分成多个段,然后将对应位置的bit填充1,实现存在性标记
布隆过滤器可以作为一种在大数据集查询前的一个存在性筛选:
布隆过滤器返回存在,则元素不一定存在,需要进行确定性查询,比如 SQL
返回不存在,元素一定不存在

rawdb

core/rawdb
底层数据库操作逻辑,

state

core/state
提供了一个状态前缀树的缓存层

types

core/types
types 包提供了基本的以太坊数据类型,比如:Transaction,Block,TransactionReceipt

vm

core/vm vm 包是以太坊虚拟机 EVM 的实现,合约代码解析执行、Gas计算都在这里执行


阅读:22
搜索
  • Linux 高性能网络编程库 Libevent 简介和示例 1882
  • Mac系统编译PHP7【20190929更新】 1726
  • Windows 安装Swoole 1537
  • Hadoop 高可用集群搭建 (Hadoop HA) 1421
  • Hadoop 高可用YARN 配置 1337
  • 小白鼠问题 1234
  • Hadoop Map Reduce 案例:好友推荐 1221
  • 自动化测试工具 Selenium 1082
  • GIT 分支管理 995
  • 一致性哈希算法说明及PHP示例 958
简介
不定期分享软件开发经验,生活经验