Tendermint共识引擎,将绝大多数node的共识记录到一条区块链中,并在所有node间复制。这条区块链可以通过各种RPC访问命令,比如从获取整条区块数据的/block?height= 命令,到获取区块头列表的/blockchain?minHeight=&maxHeight=命令,应有尽有。那么这些区块中到底存储了哪些东西呢?

区块链的魔力就在于区块中包含了一批交易、区块描述信息,并链接之前的区块。而这个“链”由两种形式组成:前区块散列;以及一组使得前区块得以commit的precommits数据(也就是下面要谈到的区块组成部分“LastCommit”)。那么,一个区块将包含三个主要部分:区块头、交易列表以及LastCommit。

另外,如果在区块链中发现一次对多个区块进行propose或vote的恶意行为,其他validator可以以交易的形式发布违规evidence,Tendermint将删除违规者,为validator清理门户。因此,区块还将包含evidence数据,这个区块就是下图中的模样。

为探讨区块实体结构,在接下来的部分,将主要围绕组成区块的实体结构展开。Block结构体定义如下所示:

type Block struct {Header     `json:"header"`Data       `json:"data"`Evidence   EvidenceData `json:"evidence"`LastCommit *Commit      `json:"last_commit"`
}

Data

组成区块的最重要内容就是交易数据了,就从Data结构体开始。

说个题外话,根据官方测算,64个validators在跨互联网的环境中,Tendermint的交易吞吐量能达到4000Txs/S。这对于我这种心心念念要把区块链应用在信息安全领域的用户来说,是个好消息。相信长期关注本订阅号的读者对下图不陌生:

是的,在《也许,只有信息安全才是区块链的未来(上)》中提到:“比特币网络每秒只能处理约7笔交易”。有人会说“你这才64个节点,当然快啊”。我想回答的是“服务于信息安全的私有链无需太多的节点”。至于如何将私有链服务于信息安全,想清楚并有了最佳实践后,《也许,只有信息安全才是区块链的未来(下)》就可以提笔了。

而在不跨互联网的数据中心环境下,随着设备性能(32 vCPU,60GB RAM)的提高,交易吞吐量也会跟着增长。

话题转回来,下面是Data结构体定义,Data结构体是由Txs字段组成。

type Data struct {// Txs that will be applied by state @ block.Height+1.// NOTE: not all txs here are valid.  We're just agreeing on the order first.// This means that block.AppHash does not include these txs.Txs Txs `json:"txs"`
}

而通过进一步观察代码会发现,类型Txs是Tx数组的切片。

// Txs is a slice of Tx.
type Txs []Tx

Tx又是什么呢,Tx是由任意字节数组构成的类型。到这里就完全明白了,区块中的交易数据内容是可变的。再将这个原则联系到比特币网络呢,人们常说比特币网络实际上是分布式账本,的确,其交易内容就是转账记录。

// Tx is an arbitrary byte array.
// NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed.
// Might we want types here ?
type Tx []byte

LastCommit

LastCommit代表前一个区块的投票信息。是Commit的指针变量,Commit则是一个简单的votes列表包装器(Precommits),每个validator对应一个vote。Commit还包含与其相关的BlockID字段。

type Commit struct {// NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order.// Any peer with a block can gossip precommits by index with a peer without recalculating the// active ValidatorSet.BlockID    BlockID `json:"block_id"`Precommits []*Vote `json:"precommits"`// contains filtered or unexported fields
}

BlockID包含了区块的两种不同Merkle根散列值。第一种是做为区块的主散列(hash),它是header中所有字段的Merkle根散列值;第二种是服务于区块共识阶段的安全协商(包含在PartsHeader字段中),是将整个区块序列化后切分成片段的Merkle根散列值。所以,BlockID在包含上述两种散列值的同时还记录了区块的片段数。

type BlockID struct {Hash        cmn.HexBytes  `json:"hash"`PartsHeader PartSetHeader `json:"parts"`
}

而在PartSetHeader结构体中,Total字段是32位有符号整数,用于记录PartSet的总数,另外,Hash字段还记录了这些PartSet的Merkle根散列值。对于PartSet的介绍可参考《Tendermint:拜占庭容错算法》。

type PartSetHeader struct {Total int          `json:"total"`Hash  cmn.HexBytes `json:"hash"`
}

现在跳出BlockID结构体,看看Precommits字段,该字段是Vote结构体的指针数组。

type Vote struct {Type             SignedMsgType `json:"type"`Height           int64         `json:"height"`Round            int           `json:"round"`Timestamp        time.Time     `json:"timestamp"`BlockID          BlockID       `json:"block_id"` // zero if vote is nil.ValidatorAddress Address       `json:"validator_address"`ValidatorIndex   int           `json:"validator_index"`Signature        []byte        `json:"signature"`
}

vote包含了validator的签名信息。其中,字段Type是字节类型SignedMsgType(type SignedMsgType byte),代表vote的类别,例如vote.Type == 1是prevote、vote.Type == 2是precommit。
Height字段表示链上顺序增长的区块位置编号,是64位有符号整数。
Round字段表示当前round的情况,是32位有符号整数。
Timestamp字段是64位有符号整数,以毫秒为单位的UNIX时间。
ValidatorAddress字段是crypto包的类型Address,是16进制编码的字节数组,用于标识validator的地址。
ValidatorIndex是32位有符号整数,用于标识validator的序号。
Signature是字节数组,用于标识validator的数字签名。Tendermint目前仅支持ED25519算法。

Header

这部分内容多,是区块链“链”的奥妙所在,Header既区块头。Header结构体由四个部分构成:区块基本信息、前区块信息、区块数据散列、前区块散列以及共识信息。

type Header struct {// basic block infoVersion  version.Consensus `json:"version"`ChainID  string            `json:"chain_id"`Height   int64             `json:"height"`Time     time.Time         `json:"time"`NumTxs   int64             `json:"num_txs"`TotalTxs int64             `json:"total_txs"`// prev block infoLastBlockID BlockID `json:"last_block_id"`// hashes of block dataLastCommitHash cmn.HexBytes `json:"last_commit_hash"` // commit from validators from the last blockDataHash       cmn.HexBytes `json:"data_hash"`        // transactions// hashes from the app output from the prev blockValidatorsHash     cmn.HexBytes `json:"validators_hash"`      // validators for the current blockNextValidatorsHash cmn.HexBytes `json:"next_validators_hash"` // validators for the next blockConsensusHash      cmn.HexBytes `json:"consensus_hash"`       // consensus params for current blockAppHash            cmn.HexBytes `json:"app_hash"`             // state after txs from the previous blockLastResultsHash    cmn.HexBytes `json:"last_results_hash"`    // root hash of all results from the txs from the previous block// consensus infoEvidenceHash    cmn.HexBytes `json:"evidence_hash"`    // evidence included in the blockProposerAddress Address      `json:"proposer_address"` // original proposer of the block
}

区块基本信息

Version字段用来标识区块链和应用程序协议的版本。由version包的Consensus结构体定义。而类型Protocol则是64位无符号整数(type Protocol uint64)。

type Consensus struct {Block Protocol `json:"block"`App   Protocol `json:"app"`
}

ChainID字段是最大长度为50的UTF-8字符串,该字段在“genesis.json”文件中定义,例如ChainID为“test-chain-nlXLFL”的区块链。
Height字段表示链上顺序增长的区块位置编号,是64位有符号整数。注意,第一个区块遵从“block.Header.Height == 1”。
Time字段是64位有符号整数,以毫秒为单位的UNIX时间。受Tendermint共识引擎管理,遵从如下原则:

  • 时间单调性:时间单调增加,例如分配header H1给height为h1的区块,则header H2满足“height h2=h1+1、H1.Time<H2.Time”;
  • 时间有效性:从block.LastCommit字段给定一组Commit votes,区块头中的Time字段值的有效范围仅由正确进程发送的Precommit消息定义(来自LastCommit字段),也就是错误的进程不能任意增加Time的值。

NumTxs字段是64位有符号整数,记录本区块中的交易数量。
TotalTxs字段是64位有符号整数,记录本区块链中包含所有交易数量的总和。注意,第一个区块遵从“block.Header.TotalTxs = block.Header.NumTxs”。

前区块信息
为了将区块链接在一起,LastBlockID字段是前区块的BlockID。注意,第一个区块遵从“block.Header.LastBlockID == BlockID{}”。

区块数据散列
LastCommitHash字段是16进制编码的字节数组,其值和LastCommitHash的Merkle根散列值一致。注意,在第一个区块中,遵从“block.Header.LastCommitHash == []byte{}”。
DataHash字段是16进制编码的字节数组,代表当前区块交易数据的Merkle根散列值。

前区块散列
ValidatorsHash字段是16进制编码的字节数组,代表当前区块validator列表的Merkle根散列值。还可以用于验证下一个区块中包含的LastCommit字段。
NextValidatorsHash字段是16进制编码的字节数组,代表可参与下一区块共识的validator列表。
ConsensusHash字段是16进制编码的字节数组,代表当前区块共识参数的amino编码散列值。
AppHash字段是16进制编码的字节数组,代表Tendermint网络在执行和提交前一个区块后返回的任意字节数组。它是验证来自ABCI接口的任何merkle证明的基础,反映的是实际应用的状态,而不是区块链本身的状态。第一个区块遵从“block.Header.AppHash == []byte{}”。
LastResultsHash字段是16进制编码的字节数组,代表前一个区块交易结果的Merkle散列值。

共识信息
EvidenceHash字段是16进制编码的字节数组,代表本区块中有拜占庭行为,也就是evidence的Merkle根散列值。
ProposerAddress字段是crypto包的类型Address,是16进制编码的字节数组,代表本区块proposer的地址。

Evidence

type EvidenceData struct {Evidence EvidenceList `json:"evidence"`// contains filtered or unexported fields
}

EvidenceData结构体由EvidenceList构成,是一个Evidence类型(type EvidenceList []Evidence)。而Evidence实际上是个接口。

type Evidence interface {Height() int64                                     // height of the equivocationAddress() []byte                                   // address of the equivocating validatorBytes() []byte                                     // bytes which compromise the evidenceHash() []byte                                      // hash of the evidenceVerify(chainID string, pubKey crypto.PubKey) error // verify the evidenceEqual(Evidence) bool                               // check equality of evidenceValidateBasic() errorString() string
}

这意味着任何Evidence的实现都可以用Amino前缀编码。Amino是一个编码库,可以很好地处理接口(和protobuf的”oneof”一样)。通过在每个“具体类型”加前缀加字节来实现。通过下面的操作就能实现符合Evidence接口的DuplicateVoteEvidence结构体。

func RegisterEvidences(cdc *amino.Codec) {cdc.RegisterInterface((*Evidence)(nil), nil)cdc.RegisterConcrete(&DuplicateVoteEvidence{}, "tendermint/DuplicateVoteEvidence", nil)
}// DuplicateVoteEvidence contains evidence a validator signed two conflicting
// votes.
type DuplicateVoteEvidence struct {PubKey crypto.PubKeyVoteA  *VoteVoteB  *Vote
}var _ Evidence = &DuplicateVoteEvidence{}// String returns a string representation of the evidence.
func (dve *DuplicateVoteEvidence) String() string {return fmt.Sprintf("VoteA: %v; VoteB: %v", dve.VoteA, dve.VoteB)}
......
...

DuplicateVoteEvidence实现了检测某个具体validator进行两次存在冲突投票的拜占庭行为的能力。

本文转载于:https://zhuanlan.zhihu.com/p/51432128

作者:Rosen Jiang

【区块链】Tendermint——实体结构相关推荐

  1. 墨客科技执行董事袁英:MOAC区块链赋能实体产业的方案与实践

    文丨互链脉搏 未经授权,不得转载! [互链脉搏按] 12月14日,由中国工业和信息化部电子第五研究所指导,互链脉搏主办的"IN-Chain全球区块链峰会"将在北京香格里拉酒店隆重召 ...

  2. 区块链与实体产业相结合加速推进数字经济智能化发展

    区块链的发展是一个理想向现实靠拢的过程,从消费层到产业级的转变. 随着数字经济的作用不断凸显,运用数字化技术,承载着可信数据网络的功能,解决了传统中心数据库在企业间无法产生信任的问题,支撑实体经济发展 ...

  3. python构建区块链_用python构建区块链(1)---基本结构

    目录 背景 比特币从诞生到现在已经10年了,最近一段时间因为工作原因接触到了区块链相关的技术,为了揭开其背后的神秘面纱,我们就从头开始构建一个简单的区块链.在行动之前我们先看一下比特币的整体结构. 比 ...

  4. 从零开发区块链应用(八)--结构体初识

    文章目录 一.结构体定义 二.初始化结构体 三.结构体的访问 四.结构体指针 五.结构体可见性 六.结构体标签 七.结构体嵌套 八.结构体方法 九.结构体特性 Go语言中提供了对struct的支持,s ...

  5. [区块链]初识R3-Corda,解析区块链结构

    网络结构 R3-Corda is for permissioned nodes to communicate on a need-to-know basis about updating shared ...

  6. 从区块链到DAG(二)--DAG的基本结构

    DAG(Directed Acyclic Graph),中文译作"有向无环图",作为一种新的底层账本结构被重新提出来."有向"指有方向,"无回&quo ...

  7. 以太坊区块链的区块(Block)结构

    这里以以太坊区块链为基础进行讲解.直接看代码: 区块结构代码:block.go 1.block的header type Header struct {ParentHash common.Hash `j ...

  8. java以太坊源码分析_以太坊区块链Java(EthereumJ)学习笔记:区块链结构-Go语言中文社区...

    本文对EthereumJ的区块链相关的代码做一个简单的介绍. 以太坊区块链 以太坊区块链是在Bitcoin区块链的基础上发展起来的.区块链的数据结构既保留了Bitcoin区块链验证数据的真实性和完整性 ...

  9. A survey on challenges and progresses in blockchain technologies区块链综述

    目录 摘要 Introuduction 2.关键技术 2.1 分布式账本 2.2 密码学 2.4.智能合约 2.5 基准 3.挑战和最先进的进步 3.1 性能关注区块链 3.2 安全问题 3.3.性能 ...

最新文章

  1. java setdate_java---Set,Date
  2. s时钟画布 android,Android UI编程进阶——使用SurfaceViewt和Canvas实现动态时钟
  3. lucene.NET详细使用与优化详解
  4. 在python中定义类时、运算符重载_python自定义类运算符重载
  5. 计算机网络——物理层设备
  6. MySQL设计说明书_数据库详细设计说明书-模板.doc
  7. 百度文库API免费下载百度文库收费资料【python】
  8. 织梦php 文章采集规则,如何正确写DedeCms采集规则
  9. 2022-07-08 Unity Json2——LitJson
  10. JAVA博客和书籍推荐
  11. FindBugs错误描述
  12. hprose php用户手册,07 Hprose 服务器事件
  13. 红米k20适配android q,比谷歌还快,红米K20 PRO首发安卓Q稳定版,只有华为心里苦...
  14. SEM: 科研图片处理
  15. 【YOLOV5-5.x 源码解读】google_utils.py
  16. Linux Ubuntu NVIDIA双显卡切换intel显卡方法, 如果无法正常切换
  17. 半加器 全加器 Verilog描述
  18. 请教modelsim中vlog的用法
  19. win10专业版虚拟机配置服务器,windows10专业版使用虚拟机Hpyer-V的办法
  20. 单机版Fate安装教程(含虚拟机搭建)

热门文章

  1. Matlab求解方程或函数的根,root,fzero,solve,fsolve的区别
  2. 3D格式转换工具HOOPS Exchange助力3D 打印软件实现质的飞跃
  3. 【WPS】excel 启用宏 windows环境
  4. unity在同屏幕显示多Camera并在脚本中修改Viewport Rece
  5. 二本计算机专业 考研究生,二本可以考上985的研究生吗?
  6. 基于JSP的健身俱乐部会员管理系统的设计与实现(论文+PPT+源码)
  7. 集成学习-Bagging原理与实现 西瓜书
  8. Android 二维码 生成和识别(附Demo源码)
  9. 值得学习的C语言开源项目
  10. 验证Tensorflow-gpu下载成功