对“初链”混合共识、双链结构和抗ASIC挖矿算法的详解

前段时间写了篇博客说了说自己对“初链”白皮书和黄皮书的解读,其中一部分涉及到对“初链”混合共识和双链技术的解读,由于是从说明文档中获取的信息,难免会有误解,虽然大体上和实际的处理逻辑相符合,但在细节上还是有一定的出入。出于对混合共识技术和双链逻辑的好奇,博主我下来抽空余时间仔细阅读了下“初链”项目共识部分的代码,感悟颇深,遂写文分享。本篇博客的目的是让对区块链有一定了解且有一定技术开发经验的朋友快速、深入地了解“初链”混合共识机制的处理逻辑,主要以源代码翻译伪代码(基于“初链”Beta版本)的形式讲解各个处理过程,因为只有用伪代码的方式才能直观的表述一个处理过程的细节,但我并不会过分深入每一个细节。本篇博客包括以下内容:

  • 快链(FastChain)、慢链(SnailChain)的区块结构、区块验证和交互机制
  • 慢链(SnailChain)的区块打包、挖矿和奖励分配机制
  • 快链(FastChain)的区块打包和拜占庭委员会(PBFT)的共识机制
  • 拜占庭委员会(PBFT)的选举和验证机制
  • 抗ASIC专用矿机的POW挖矿算法(TrueHash)
  • “初链”和以太坊的关系
  • “初链”的代码审查意见
  • 总结

> 快链(FastChain)、慢链(SnailChain)的区块结构、区块验证和交互机制

“初链”采用双链结构设计,目的是为了分离交易确认和算力保护。快链区块直接打包交易,交易打包成区块后经过拜占庭委员会(PBFT)的共识即被确认,此过程很快。慢链区块包含快链区块的内容,通过挖矿完成慢链区块的打包,慢链采用工作量证明(POW)机制,旨在通过算力保护整个区块链和拜占庭委员会的安全。

快链区块结构(FastBlock:code/types/block.go)<
// Header represents a block header in the true Fastblockchain.
type Header struct {
   
    ParentHash  common.Hash `json:"parentHash"       gencodec:"required"`
    Root        common.Hash `json:"stateRoot"        gencodec:"required"`
    TxHash      common.Hash `json:"transactionsRoot" gencodec:"required"`
    ReceiptHash common.Hash `json:"receiptsRoot"     gencodec:"required"`
    Bloom       Bloom       `json:"logsBloom"        gencodec:"required"`
    SnailHash   common.Hash `json:"snailHash"        gencodec:"required"`
    SnailNumber *big.Int    `json:"snailNumber"      gencodec:"required"`
    Number      *big.Int    `json:"number"           gencodec:"required"`
    GasLimit    uint64      `json:"gasLimit"         gencodec:"required"`
    GasUsed     uint64      `json:"gasUsed"          gencodec:"required"`
    Time        *big.Int    `json:"timestamp"        gencodec:"required"`
    Extra       []byte      `json:"extraData"        gencodec:"required"`
}

// FastBlock represents an entire block in the Ethereum blockchain.
type Block struct {
   
    header       *Header
    transactions Transactions

    uncles []*Header // reserved for compile

    signs PbftSigns

    // caches
    hash atomic.Value
    size atomic.Value

    // Td is used by package core to store the total difficulty
    // of the chain up to and including the block.
    // td *big.Int

    // These fields are used by package etrue to track
    // inter-peer block relay.
    ReceivedAt   time.Time
    ReceivedFrom interface{
   }
}

在快链区块结构中,最重要的两个属性就是"transactions"和"signs",在区块头中也可以看到有“TxHash”、“GasLimit”和“GasUsed”这三个属性,这表明了快链区块的主要作用是执行交易、收集交易和收集拜占庭委员会成员的签名。

慢链区块结构(FastBlock:code/types/block.go)<
// Header represents a block header in the Ethereum truechain.
type SnailHeader struct {
   
    ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
    UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
    Coinbase    common.Address `json:"miner"            gencodec:"required"`
    PointerHash common.Hash    `json:"PointerHash"      gencodec:"required"`
    FruitsHash  common.Hash    `json:"fruitsHash"       gencodec:"required"`
    FastHash    common.Hash    `json:"fastHash"         gencodec:"required"`
    FastNumber  *big.Int       `json:"fastNumber"       gencodec:"required"`
    SignHash    common.Hash    `json:"signHash"  		gencodec:"required"`
    Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
    Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
    Number      *big.Int       `json:"number"           gencodec:"required"`
    Publickey   []byte         `json:"Publickey"        gencodec:"required"`
    ToElect     bool           `json:"ToElect"          gencodec:"required"`
    Time        *big.Int       `json:"timestamp"        gencodec:"required"`
    Extra       []byte         `json:"extraData"        gencodec:"required"`
    MixDigest   common.Hash    `json:"mixHash"          gencodec:"required"`
    Nonce       BlockNonce     `json:"nonce"            gencodec:"required"`

    Fruit bool
}

// Block represents an entire block in the Ethereum blockchain.
type SnailBlock struct {
   
    header *SnailHeader
    fruits SnailBlocks
    signs  PbftSigns

    uncles []*SnailHeader

    // caches
    hash atomic.Value
    size atomic.Value

    // Td is used by package core to store the total difficulty
    // of the chain up to and including the block.
    td *big.Int

    // These fields are used by package etrue to track
    // inter-peer block relay.
    ReceivedAt   time.Time
    ReceivedFrom interface{
   }
}

慢链区块有点特殊,在“初链”中包含“水果(Fruit)”的概念,而水果也是通过慢链区块来表示的。在慢链区块中包含“fruits”、“signs”属性,在区块头中则包含很多属性,其中包括有“Coinbase”、“PointerHash”、“FruitsHash”、“FastHash”、“SignHash”、“ToElect”和“Fruit”属性。这些里面最能直观反应慢链区块的作用的就是块中的“fruits”、“signs”属性和头中“Fruit”属性。区块头中的“Fruit”布尔属性表明该区块是不是一个水果,如果是水果,那在块中就有“signs”属性填充,否则就是一个普通区块,在块中有“fruits”属性填充。这三个属性直观地表明了“水果”和“区块”的关系:水果是包含了一个快链区块(FastBlock)中拜占庭委员会成员签名的区块,而真正意义上的区块则是包含了多个连续排列的水果(头中“FastNumber”属性顺序排列)的区块。

快链区块的验证(VerifyFastBlock:etrue/pbft_agent.go)<

拜占庭共识委员会在收集P2P网络中的交易并产生快链区块后,或者收到其他委员会广播的区块后,会进行区块验证,该算法的流程大致是:

  1. 验证父区块是否存在
  2. 验证区块头
  3. 验证区块体
  4. 验证交易和状态数据库

伪代码如下:

// 传入快链区块 => fb type.FastBlock,bc type.BlockChain
// 验证父区块
parent = bc.GetBlock(fb.ParentHash(), fb.Number()-1)
if parent == nil {
   
    return error("height not yet")
}
// 验证区块头
header = fb.Header()
if len(header.Extra) > 32 {
   
    return error("extra too long")
}
if header.Time - Time.Now() > 15 * Time.Second {
   
    return error("future block")
}
if header.Time < parent.Time {
   
    return error("zero block time")
}
if header.GasLimit > 0x7fffffffffffffff {
   
    return error("invalid gas used")
}
if abs(parent.GasLimit - header.GasLimit) >= (parent.GasLimit / 1024) || header.GasLimit < 5000 {
   
    return error("invalid gas limit")
}
if header.Number - parent.Number != 1 {
   
    return error("invalid number")
}
//  验证区块体
if Hash(fb.Transactions()) != header.TxHash {
   
    return error("transaction root hash mismatch")
}
// 验证交易和状态数据库
stateDB = fb.State()
receipts, usedGas = bc.Process(fb.Transactions(), stateDB)
if fb.GasUsed() != usedGas {
   
    return error("invalid gas used")
}
if CreateBloomHash(receipts) != header.Bloom {
   
    return error("invalid bloom")
}
if Hash(receipts) != header.ReceiptHash {
   
    return error("nvalid receipt root hash")
}
if Hash(state) != header.Root {
   
    return error("invalid merkle root")
}
return nil
慢链区块的验证(ValidateFruit:core/snailchain/block_validator.go、VerifySnailHeader:consensus/minerva/consensus.go)<

慢链区块由于分为水果和区块,所以有两种验证过程:

  1. 区块
    a) 验证区块头
    b) 验证区块体
  2. 水果
    a) 验证委员会签名
    b) 验证水果新鲜度
    c) 验证区块头

验证区块伪代码如下:

// 传入慢链区块 => sb type.SnailBlock,bc type.SnailBlockChain
// 验证区块头
parent = bc.GetBlock(sb.ParentHash(), sb.Number()-1)
if parent == nil {
   
    return error("unkown ancestor")
}
header = fb.Header()
if len(header.Extra) > 32 {
   
    return error("extra too long")
}
if header.Time - Time.Now() > 15 * Time.Second {
   
    return error("future block")
}
if header.Time < parent.Time {
   
    return error("zero block time")
}
expectedDifficulty = CalcSnailDifficulty(bc, header.Time, parent)
if expectedDifficulty != header.Difficulty {
   
    return error("invalid difficulty")
}
digest, hashResult = truehash(header.HashWithoutNonce(), header.Nonce)	// 挖矿时计算的数据指纹和哈希结果
if header.MixDigest != Hash(digest) {
   
    return error("invalid mixdigest")
}
maxUint128 = 2 ^ 128 - 1
if hashResult.SubBytes(0, 15) > (maxUint128 / header.Difficulty) {
       // hashResult取前16字节
    return error("invalid pow")
}
// 验证区块体
for fruit in range sb.Fruits() {
   
    if err = ValidateFruit(fruit, bc); err != nil {
   
        return err
    }
}
return nil

验证水果伪代码如下:

// 传入水果 => f type.SnailBlock,bc type.SnailBlockChain
// 验证委员会签名
header = f.Header()
if Hash(f.Signs()) != header.SignHash {
   
    return error("invalid sign")
}
// 验证水果新鲜度
pointer = bc.GetBlockByHash(f.PointerHash())	     // pointer区块是在水果生成时从当前慢链区块往前数7个的那个区块
if pointer == nil {
   
    return error("invalid pointer")
}
if bc.CurrentBlock().Number() - pointer.Number() > 17 {
       // 生成水果时指定的区块高高度比最新的区块高度低17位时则水果过期
    return error("invalid freshness")	    // 水果的生存周期只有(17-7)=10个区块,每个区块生产周期为10分钟,所以水果的新鲜度只有平均1个小时40分钟左右
}
// 验证区块头
parent = bc.GetBlock(f.ParentHash(), f.Number()-1)
if parent == nil {
   
    return error("unkown ancestor")
}
if len(header.Extra) > 32 {
   
    return error("extra too long")
}
digest, hashResult = truehash(header.HashWithoutNonce(), header.Nonce)
if header.MixDigest != Hash(digest) {
   
    return error("invalid mixdigest")
}
fruitDifficulty = pointer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值