- 快召唤伙伴们来围观吧
- 微博 QQ QQ空间 贴吧
- 文档嵌入链接
- 复制
- 微信扫一扫分享
- 已成功复制到剪贴板
基于Go-Ethereum构建DPOS机制下的区块链
展开查看详情
1 .基于Go-Ethereum构建DPOS机制下的区块链 恺英⽹网络—朱崇⽂文
2 .⽬目录 1 Go版本以太坊 2 为何选择DPOS机制 3 拓拓展共识改造实战 4 智能合约的实践 5 压⼒力力测试下暴暴露露的问题
3 .Go版本以太坊 以太坊的客户端 Geth • Go、官⽅方版本实现 Parity • Rust的实现,第⼆二⼤大客户端 以太坊技术协议 cpp-ethereum ethereumj
4 .Go版本以太坊 以太坊的⼯工具组 Truffle Solidity 以太坊核⼼心组件 以太坊相关⼯工具组 Metamask Web3.js mist IFPS (Go) 以太坊外部存储 Swarm(Go)
5 .Go版本以太坊 以太坊公链⽹网络拓拓扑
6 .为何选择DPOS机制 共识机制对⽐比 POW • 消耗计算⼒力力 • 出块速度慢,确认慢 • TPS极低 10~20 • 确认 1分钟+ DPOS • 代理理⼈人模式 • 出块速度快,确认快 • TPS 700~1000 (实现) • 平均确认1~3秒
7 .为何选择DPOS机制 DPOS机制的优势 系统可靠性 • 在商业场景下,⽹网络性能可控 • 对异常情况能快速处理理并恢复 • 对TPS/QPS,以及确认性能有⼀一定要求 区块链可信 • 以公有链为基础,可对外开放 • 任何⼈人都可以参与,设⽴立理理事会和⻅见证⼈人⻆角⾊色 • 理理事会管理理区块链⽹网络 • ⻅见证⼈人⽣生产并验证区块
8 . 为何选择DPOS机制 理理事会成员 DPOS机制的理理念 委任⻅见证⼈人 ⻅见证⼈人 (矿⼯工) 选举理理事会 社区成员 A B C A ⽣生产/验证区块
9 .拓拓展共识改造实战 共识框架引擎—改造共识层逻辑
10 .拓拓展共识改造实战 共识框架引擎—官⽅方实现引擎: Ethash / Clique // Engine is an algorithm agnostic consensus engine. type Engine interface { Author(header *types.Header) (common.Address, error) VerifyHeader(chain ChainReader, header *types.Header, seal bool) error VerifyHeaders(chain ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) VerifyUncles(chain ChainReader, block *types.Block) error VerifySeal(chain ChainReader, header *types.Header) error Prepare(chain ChainReader, header *types.Header) error Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int APIs(chain ChainReader) []rpc.API }
11 .拓拓展共识改造实战 共识框架引擎—Seal核⼼心⽅方法调⽤用 Import Block 其他节点产⽣生区块 // Seal generates a new block for the given input block with the local miner's // seal place on top. Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) go Agent.update work channel go Engine.Seal Result go Worker.wait result channel commit new work
12 .拓拓展共识改造实战 借鉴Clique(POA)的实现 跳过步⻓长 n/2 Difficult=2 Clique • Go-Ethereum 实现的机制, A B C • In turn ⽤用以公共测试链 • 整个⽹网络由Signer节点出块 • Signer节点可以投票选择其他Signer节点 A • No turn • 节点之间可以相互竞争出块 • 存活节点数 > (n/2) + 1 • Signer 节点的选举记录在Extra Data中 Difficult=1
13 .拓拓展共识改造实战 借鉴Clique(POA)的实现 • 满⾜足条件,竞争出块 // Sweet, the protocol permits us to sign the block, wait for our time delay := time.Unix(header.Time.Int64(), 0).Sub(time.Now()) // nolint: gosimple • ⾮非⾃自⼰己的轮次,⼩小⼩小的延迟 if header.Difficulty.Cmp(diffNoTurn) == 0 { // It's not our turn explicitly to sign, delay it a bit wiggle := time.Duration(len(snap.Signers)/2+1) * wiggleTime delay += time.Duration(rand.Int63n(int64(wiggle))) select { case <-stop: return nil, nil case <-time.After(delay): } 竞争出块的节点有⼀一点延迟,避免过多分叉
14 .拓拓展共识改造实战 扩展区块头结构—增加⻅见证⼈人列列表 区块头结构 // Header represents a block header in the Ethereum blockchain. type Header struct { • 框架程度较⾼高 ParentHash common.Hash `json:"parentHash" gencodec:"required"` UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` 很容易易扩展字段 Coinbase common.Address `json:"miner" gencodec:"required"` Root common.Hash `json:"stateRoot" gencodec:"required"` • 地址按字典排序 ------------ ----------------- WitnessVotes WitnessVoteSlice `json:"witnessVotes" gencodec:"required"` } witnessVotes: [{ address: "0x36114a04a4f621da0f19b8453f414cf1f0c40757" }, { address: "0x45db4d996660a6cf312ccf2a6e42fb723bab1be5" 数据案例例 }, { address: "0x6e2059b7aabc5179a01a5b54523747b15620b4e3" }, { address: "0xa2477cadf6b3531072d11dab58e76729346baa69" }, { address: "0xe0263a75d6b7f5ebdcce6546bed9e7b6102a2d8d" }]
15 .拓拓展共识改造实战 扩展区块头结构—⻅见证⼈人列列表⽣生成规则 扩展区块头结构 ⻅见证⼈人列列表 Block n+1 ⻅见证⼈人a (a,b) • 区块N的⻅见证⼈人列列表为区块(N-1) 所达成共识的⻅见证⼈人 Block n ⻅见证⼈人 ⻅见证⼈人列列表 …………………. ⻅见证⼈人列列表 Block-0 0x000…000 (初始)
16 .拓拓展共识改造实战 轮流⽣生产者的实现 — 判断当前轮次是否需要产块 • 当前时间戳 • 当前区块的产块⼈人 is_step_proposer • Parent区块的⻅见证⼈人 • Parent区块的时间戳 • 产块周期
17 .拓拓展共识改造实战 轮流⽣生产者的实现 — 场景分析 • 产块周期3秒 , 当前时间T+3 • 三个⻅见证⼈人节点判断该时间点是否应该出块 ⻅见证⼈人列列表 Timestamp Parent Block n ⻅见证⼈人 a (a,b,c) T ⻅见证⼈人列列表 Timestamp 节点A Block n+1 ⻅见证⼈人 a (a,b,c) T+3 ⻅见证⼈人列列表 Timestamp 节点B Block n+1 ⻅见证⼈人 b (a,b,c) T+3 ⻅见证⼈人列列表 Timestamp 节点C Block n+1 ⻅见证⼈人 c (a,b,c) T+3
18 .拓拓展共识改造实战 轮流⽣生产者的实现 — 判断当前轮次—代码实现 // parent的signer存在于合法签发列列表中 if parentOk { delta = int64(math.Abs(float64(currentIndex) - float64(parentIndex))) // 上⼀一个签发的是⾃自⼰己,则等待len(Signers)周期 if delta == 0 { delta = int64(len(snap.Signers)) } else { 计算与Parent块 // 如果 p 在 c 后⾯面,从P开始计算差 之间的轮次差值 if (parentIndex > currentIndex) { delta = signsLength - delta } } } else { // parent不不在当前 singer list中, 则默认从当前的index + 1开始计算delta delta = int64(currentIndex + 1) } ------------ ----------------- ------------ 和当前出块时间⽐比较 ----------------- if (parentTimestamp + delta * period ) <= currentHeaderTime { return true }
19 .拓拓展共识改造实战 轮流⽣生产者的实现 — 注册下⼀一次调⽤用 — 原因 Import Block 其他节点产⽣生区块 • Seal失败,则不不会触发下⼀一次Seal调⽤用 • 其他节点故障,不不会触发Seal调⽤用 go Agent.update work channel go Engine.Seal Result go Worker.wait result channel commit new work
20 .拓拓展共识改造实战 轮流⽣生产者的实现 — 注册下⼀一次调⽤用 — 场景分析 • 注册下⼀一次delay时间,最⼤大值是3秒,防⽌止陷⼊入side fork • 最⼩小值 = (3-块打包消耗时间) ⻅见证⼈人列列表 Timestamp Parent Block n ⻅见证⼈人 a (a,b,c) T ⻅见证⼈人列列表 Timestamp 节点A Block n+1 ⻅见证⼈人a (a,b,c) T+3 Delay len(a,b,c)*3 - 3
21 .拓拓展共识改造实战 轮流⽣生产者的实现 — 注册下⼀一次调⽤用 — 代码实现 • Seal⽅方法中,通过defer来注册下⼀一次调⽤用 // 注册返回函数,执⾏行行下⼀一次mine defer func() { var duration = time.Duration(c.config.Period) * time.Second var currentTimeStamp = time.Now().Unix() // 没有赋值,等待⼀一个默认周期 计算delay时间 if nextTimeStamp == 0 { go c.registerNextDurationTimer(duration) } else { var interval int64 // 如果进度滞后,duration = 0 if currentTimeStamp >= nextTimeStamp { interval = 0 } else { // duration时间不不超过⼀一个周期,防⽌止陷⼊入 side fork interval = min(nextTimeStamp - currentTimeStamp, int64(c.config.Period)) } duration := time.Duration(interval) * time.Second go c.registerNextDurationTimer(duration) 注册函数 } }()
22 .拓拓展共识改造实战 轮流⽣生产者的实现 — ⾃自定义奖励规则 • 抽象奖励逻辑 • 实现多种奖励策略略
23 . 拓拓展共识改造实战 轮流⽣生产者的实现 — ⾃自定义奖励规则 "config": { "board": { 创世块配置中设置奖励规则 "period": 3, "reward":"default_reward" } }, 定义奖励规则接⼝口 type Reward interface AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header) var BoardBlockReward *big.Int = big.NewInt(5e+18) // 每⼀一个witness产块的奖励 //默认产币规则,每⼀一个block奖励5个coin给予⻅见证者 func (c *DefaultReward) AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header) { reward := new(big.Int).Set(BoardBlockReward) 实现默认规则 state.AddBalance(header.Coinbase, reward) }
24 .智能合约的实践 合约语⾔言Solidity
25 .智能合约的实践 实现投票合约 — 理理事会
26 .智能合约的实践 实现投票合约 — ⻅见证⼈人
27 .智能合约的实践 智能合约设计模式 • 合约控制器器模式设计 • 逻辑层和存储层分离 Business_1 Controller DataStorage Business_2
28 .智能合约的实践 智能合约并不不智能,反⽽而有太多坑 1. 函数参数不不能超过7个 2. 函数参数不不能是任何变⻓长对象的数组,例例如string[],uint[][6] 3. 合约之间调⽤用不不能传递变⻓长数组,例例如uint[],只能传递定⻓长数组,例例如uint[6] 4. ⼆二维数组的定义⽅方式与⼤大多数语⾔言相反,例例如:uint[][6]表示⼀一个⻓长度为5的uint数组,每个元 素⼜又是⼀一个变⻓长数组 5. 只有internal和private的function才能使⽤用结构类型的参数 6. mapping不不可遍历,⼀一个可以遍历的版本https://github.com/ethereum/dapp-bin/blob/ master/library/iterable_mapping.sol 7. delete不不同对象有不不同的效果,主要为重置为初始值,⽽而⾮非真正删除该对象,详⻅见https:// baijiahao.baidu.com/s?id=1566265348199485&wfr=spider&for=pc 8. 不不要在view⽅方法中使⽤用event,这会导致失去view限制,消耗gas,并导致⽤用户调⽤用⽅方式的改 变 9. 合约创建的⼤大⼩小不不能过⼤大,24k
29 .智能合约的实践 智能合约设计模式, 使⽤用单⼀一合约 Business_1 Controller Business_2 Single Business