IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 以太坊POA共识算法解析 -> 正文阅读

[区块链]以太坊POA共识算法解析

1.clique中的概念和定义

  • EPOCH_LENGTH?: epoch长度是30000个block, 每次进入新的epoch,前面的投票都被清空,重新开始记录,这里的投票是指加入或移除signer
  • BLOCK_PERIOD?: 出块时间, 默认是15s
  • UNCLE_HASH?: 总是?Keccak256(RLP([]))?,因为没有uncle
  • SIGNER_COUNT?: 每个block都有一个signers的数量
  • SIGNER_LIMIT?: 等于?(SIGNER_COUNT / 2) + 1?. 每个singer只能签名连续SIGNER_LIMIT个block中的1个
    • 比如有5个signer:ABCDE, 对4个block进行签名, 不允许签名者为ABAC, 因为A在连续3个block中签名了2次
  • NONCE_AUTH?: 表示投票类型是加入新的signer; 值=?0xffffffffffffffff
  • NONCE_DROP?: 表示投票类型是踢除旧的的signer; 值=?0x0000000000000000
  • EXTRA_VANITY?: 代表block头中Extra字段中的保留字段长度: 32字节
  • EXTRA_SEAL?: 代表block头中Extra字段中的存储签名数据的长度: 65字节
  • IN-TURN/OUT-OF-TURN?: 每个block都有一个in-turn的signer, 其他signers是out-of-turn, in-turn的signer的权重大一些, 出块的时间会快一点, 这样可以保证该高度的block被in-turn的signer挖到的概率很大.
  • 创世块中的Extra字段包括:
    • 32字节的前缀(extraVanity)
    • 所有signer的地址
    • 65字节的后缀(extraSeal): 保存signer的签名
  • 其他block的Extra字段只包括extraVanity和extraSeal
  • Time字段表示产生block的时间间隔是:blockPeriod(15s)
  • Nonce字段表示进行一个投票: 添加( nonceAuthVote:?0xffffffffffffffff?)或者移除( nonceDropVote:?0x0000000000000000?)一个signer
  • Coinbase字段存放?被投票?的地址
    • 举个栗子: signerA的一个投票:加入signerB, 那么Coinbase存放B的地址
  • Difficulty字段的值: 1-是?本block的签名者?(in turn), 2-?非本block的签名者?(out of turn)

2. PoA的特点

  • PoA是依靠预设好的授权节点(signers),负责产生block。普通节点不能挖矿无生成区块的权利
  • 可以由已授权的signer选举(投票超过50%)加入新的signer。
  • 即使存在恶意signer,他最多只能攻击连续块(数量是 (SIGNER_COUNT / 2) + 1)?中的1个,期间可以由其他signer投票踢出该恶意signer。
  • 可指定产生block的时间。
  • 无挖矿奖励

3. PoA的工作流程及接口

  1. 在创世块中指定一组初始授权的signers, 所有地址保存在创世块Extra字段中
  2. 启动挖矿后, 该组signers开始对生成的block进行 签名并广播.
  3. 签名结果?保存在区块头的Extra字段中
  4. Extra中更新当前高度已授权的 所有signers的地址?,因为有新加入或踢出的signer
  5. 每一高度都有一个signer处于IN-TURN状态, 其他signer处于OUT-OF-TURN状态, IN-TURN的signer签名的block会 立即广播?, OUT-OF-TURN的signer签名的block会 延时?一点随机时间后再广播, 保证IN-TURN的签名block有更高的优先级上链
  6. 如果需要加入一个新的signer, signer通过API接口发起一个proposal, 该proposal通过复用区块头 Coinbase(新signer地址)和Nonce("0xffffffffffffffff")?字段广播给其他节点. 所有已授权的signers对该新的signer进行"加入"投票, 如果赞成票超过signers总数的50%, 表示同意加入
  7. 如果需要踢出一个旧的signer, 所有已授权的signers对该旧的signer进行"踢出"投票, 如果赞成票超过signers总数的50%, 表示同意踢出

signer对区块头进行签名

  1. Extra的长度至少65字节以上(签名结果是65字节,即R, S , V, V是0或1)
  2. 对blockHeader中所有字段除了Extra的 后65字节?外进行 RLP编码
  3. 对编码后的数据进行 Keccak256?hash
  4. 签名后的数据(65字节)保存到Extra的 后65字节?中

clique.go中实现了consensus中的所有接口完成POA算法的实现

Clique.Prepare(chain , header)

Prepare是共识引擎接口之一. 该函数配置header中共识相关的参数(Cionbase, Difficulty, Extra, MixDigest, Time)

  • 对于非epoch的block(?number % Epoch != 0?):
  1. 得到Clique.proposals中的投票数据(例:A加入C, B踢除D)
  2. 根据snapshot的signers分析投票数否有效(例: C原先没有在signers中, 加入投票有效, D原先在signers中,踢除投票有效)
  3. 从被投票的地址列表(C,D)中,?随机选择一个地址?,作为该header的Coinbase,设置Nonce为加入(?0xffffffffffffffff?)或者踢除(?0x0000000000000000?)
  4. Clique.signer?如果是本轮的签名者(in-turn), 设置header.Difficulty = diffInTurn(1), 否则就是diffNoTurn(2)
  5. 配置header.Extra的数据为[?extraVanity?+?snap中的全部signers?+?extraSeal?]
  6. MixDigest需要配置为nil
  7. 配置时间戳:Time为父块的时间+15s

共识引擎clique的初始化

在?Ethereum.StartMining?中,如果Ethereum.engine配置为clique.Clique, 根据当前节点的矿工地址(默认是acounts[0]), 配置clique的?签名者?:?clique.Authorize(eb, wallet.SignHash)?,其中?签名函数?是SignHash,对给定的hash进行签名.

Clique.snapshot(chain,number,hash,parents)

快照在指定的时间内检索授权的快照,首先封装了在内存和磁盘中,寻找快照;

如果是在创世区块中则创建一个新的快照;

如果没有区块头的快照,则收集区块向后移,有明确的父就强制到父,没有明确的父到数据库中找

找到快照后,将所有的header的后半部分前移

再通过区块头生成一个新的快照,将当前区块的hash保存到最近的快照中,将生成的快照保存到磁盘上

Snapshot.apply(headers)

创建一个新的授权signers的快照, 将从上一个snapshot开始的区块头中的proposals更新到最新的snapshot上

  1. 对入参headers进行完整性检查: 因为可能传入多个区块头,?block号必须连续
  2. 遍历所有的header, 如果block号刚好处于epoch的起始(number%Epoch == 0),将snapshot中的Votes和Tally复位(?丢弃历史全部数据?)
  3. 对于每一个header,从签名中得到?signer
  4. 如果该signer在snap.Recents中, 说明?最近已经有过签名?, 不允许再次签名, 返回空
  5. 记录?该signer是该block的签名者:?snap.Recents[number] = signer
  6. 统计header.Coinbase的投票数,如果?超过signers总数的50%
  7. 执行加入或移除操作
  8. 删除snap.Recents中的一个signer记录: key=number- (uint64(len(snap.Signers)/2 + 1)), 表示释放该signer,下次可以对block进行签名了
  9. 清空被移除的Coinbase的投票
  10. 移除snap.Votes中该Conibase的所有投票记录
  11. 移除snap.Tally中该Conibase的所有投票数记录

?Clique.Seal(chain, block , stop)

Seal也是共识引擎接口之一. 该函数用clique.signer对block的进行签名. 实现共识,引擎,尝试使用创建密封块

可对一个调用过 Finalize()的区块进行授权或封印,成功时返回的区块全部成员齐整,可视为一个正常区块,可被广播到整个网络中,也可以被插入区块链等

  • 不支持密封genesis区块
  • 如果signer没有在snapshot的signers中,不允许对block进行签名
  • signer不是本区块的签名者需要延时随机一段时候后再签名,是本区块的签名者则直接签名
  • 当前签名者在‘最近签名者’中,则等待下一个epoch
  • 不支持0-period的链,不支持空块密封,没有奖励但是能够密封
  • 把签名的结果用copy替换保存到区块头Extra字段的extraSeal的65字节中中

Clique.VerifySeal(chain, header)

VerifySeal也是共识引擎接口之一.

  1. 从header的签名中恢复账户地址,改地址要求在snapshot的signers中
  2. 检查区块头中的计算难度是否匹配(in turn或out of turn)

Clique.Finalize

Finalize也是共识引擎接口之一. 该函数生成一个block, 没有叔块处理,也没有奖励机制

  1. header.Root?: 状态根保持原状
  2. header.UncleHash?: 为nil
  3. types.NewBlock(header, txs, nil, receipts)?: 封装并返回最终的block

API.Propose(addr, auth)

添加一个proposal: 调用者对addr的投票, auth表示加入还是踢出

verifyUncles(chain,block)

判断block中的叔伯块是否大于零,由于这个共识中不允许有叔伯块

ecercover(header,sigcache)

从签名头中提取以太坊帐户地址

CalcDifficulty(chain,time,parent)

返回区块的计算难度,计算难度是难度调整算法

Difficulty字段的值: 1-是?本block的签名者?(in turn), 2-?非本block的签名者?(out of turn)

投票策略

因为blockchain可能会小范围重组(small reorgs), 常规的投票机制(cast-and-forget, 投票和忘记)可能不是最佳的,因为包含单个投票的block可能不会在最终的链上,会因为已有最新的block而被抛弃。

一个简单但有效的办法是对signers配置"提议(proposal)".例如 "add 0x...", "drop 0x...", 有多个并发的提议时, 签名代码"随机"选择一个提议注入到该签名者签名的block中,这样多个并发的提议和重组(reorgs)都可以保存在链上.

该列表可能在一定数量的block/epoch 之后过期,提案通过并不意味着它不会被重新调用,因此在提议通过时不应立即丢弃。

  • 加入和踢除新的signer的投票都是立即生效的,参与下一次投票计数
  • 加入和踢除都需要 超过当前signer总数的50%?的signer进行投票
  • 可以踢除自己(也需要超过50%投票)
  • 可以并行投票(A,B交叉对C,D进行投票), 只要最终投票数操作50%
  • 再没进入新的epoch对于以一个signer的投票未被通过时,后面有其他signer对该signer的投票也算入判断中
  • 进入一个新的epoch, 所有之前的pending投票都作废, 重新开始统计投票

投票场景举例

  • ABCD, AB先分别踢除CD, C踢除D, 结果是剩下ABC
  • ABCD, AB先分别踢除CD, C踢除D, B又投给C留下的票, 结果是剩下ABC
  • ABCD, AB先分别踢除CD, C踢除D, 即使C投给自己留下的票, 结果是剩下AB
  • ABCDE, ABC先分别加入F(成功,ABCDEF), BCDE踢除F(成功,ABCDE), DE加入F(失败,ABCDE), BCD踢除A(成功, BCDE), B加入F(由于DE加入F还存在,此时BDE加入F,满足超过50%投票), 结果是剩下BCDEF

4. PoA中的攻击及防御

  • 恶意签名者(Malicious signer). 恶意用户被添加到签名者列表中,或签名者密钥/机器遭到入侵. 解决方案是,N个授权签名人的列表,任一签名者只能对每K个block签名其中的1个。这样尽量减少损害,其余的矿工可以投票踢出恶意用户。
  • 审查签名者(Censoring signer). 如果一个签名者(或一组签名者)试图检查block中其他signer的提议(特别是投票踢出他们), 为了解决这个问题,我们将签名者的允许的挖矿频率限制在1/(N/2)。如果他不想被踢出出去, 就必须控制超过50%的signers.
  • "垃圾邮件"签名者(Spamming signer). 这些signer在每个他们签名的block中都注入一个新的投票提议.由于节点需要统计所有投票以创建授权签名者列表, 久而久之之后会产生大量垃圾的无用的投票, 导致系统运行变慢.通过epoch的机制,每次进入新的epoch都会丢弃旧的投票
  • 并发块(Concurrent blocks). 如果授权签名者的数量为N,我们允许每个签名者签名是1/K,那么在任何时候,至少N-K个签名者都可以成功签名一个block。为了避免这些block竞争( 分叉?),每个签名者生成一个新block时都会加一点随机延时。这确保了很难发生分叉。

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2021-10-23 12:33:54  更:2021-10-23 12:34:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:13:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码