区块链专题(九)Tendermint - 2

论坛 期权论坛 期权     
浙商国际财经评论   2020-3-28 02:43   1307   0





来源:Unsplash

01
状态(State)


1  State


该状态包含那些在块头中拥有密码摘要的信息,因此对于验证新块是必需的。例如,验证器集和事务处理结果从不包含在块中,但它们的Merkle根包含在块中——状态信息一直对其进行记录。


State对象本身是实现细节,因为它永远不会被包含在块中或通过网络广播,而且也从不计算其哈希值。因此,此处不包含有关State如何持久或查询对象的详细信息。也就是说,它包含的类型是规范的一部分,因为它们的Merkle根包含在块中,并且它们的值用于验证。



硬编码限制为10000个验证者。这是从提交中的投票数限制继承来的。 1.1 结果


Result是针对应用程序执行事务的结果。它返回结果代码和任意字节数组(即返回值)。需要更新结果以包括处理交易中返回的更多字段,例如气体变量和标签。 1.2 验证器(Validator)验证者是共识机制的积极参与者,具有公钥和投票权。验证程序还包含一个地址字段,该字段是PubKey的哈希摘要。


当Validator结构进行哈希映射时,不包括该地址,因为它与pubkey无关。
state.Validators,state.LastValidators和state.NextValidators,必须始终验证地址进行排序,以便计算MerkleRoot的顺序。
我们还定义了一个TotalVotingPower函数,以返回总投票权:


1.3 共识参数(ConsensusParams)ConsensusParams为区块链数据结构定义了各种限制。像验证程序集一样,它们在生成期间进行设置,并且可以由应用程序通过ABCI进行更新。进行散列处理时,仅包含参数的子集,以使参数得以演化而不会破坏标题。


1.3.1 Block块的总大小受字节限制ConsensusParams.Block.MaxBytes。块必须小于此大小,否则将被视为无效。块还应受区块中交易消耗的“气体”数量限制,尽管尚未实现。连续块之间的最短时间由ConsensusParams.Block.TimeIotaMs控制。 1.3.2 证据(Evidence)为了使块中的证据有效,必须满足:


1.3.3 验证器(Validator)验证器来自创始文件,并且ResponseEndBlock的公钥类型必须在集合 ConsensusParams.Validator.PubKeyTypes中。
02
编码方式(Encoding)

1  Amino
Tendermint 对所有数据结构使用proto3派生的Amino。将Amino视为具有原生JSON支持的面向对象协议。Amino编码协议的目标是在应用程序逻辑对象和持久性对象之间实现奇偶校验。
值得注意的是,每个满足接口的对象(例如,特定类型的p2p消息或特定类型的pubkey)都注册有全局名称,该名称的哈希值作为所谓的“前缀字节”包含在对象的编码中。
在此定义func AminoEncode(obj interface{}) []byte函数以接受任意对象并返回Amino编码的字节。 2  字节数组(Byte Arrays)
字节数组的编码就是原始字节,其原始前缀为数组的长度,即UVarint(原型称为Varint)。
例如,字节阵列[0xA, 0xB]将被编码为0x020A0B,同时含有300个entires开头的字节数组[0xA, 0xB, ...]将被编码为0xAC020A0B...其中0xAC02是300 UVarint编码。 3  哈希运算(Hashing)
Tendermint将SHA256用作其哈希函数。在进行哈希之前,对象总是经过Amino编码的。因此SHA256(obj)是SHA256(AminoEncode(obj))的缩写。 4  公钥密码方法(Public Key Cryptography)
Tendermint使用Amino来区分不同类型的私钥、公钥和签名。此外,对于每个公共密钥,Tendermint定义了一个Address函数,可以代替公共密钥成为更紧凑的标识符。在这里,我们列出了公共密钥和签名的具体类型,其名称、前缀字节,以及每个PubKey的地址。为简便起见,不包含私钥的类型和名称以外的详细信息,因为私钥的使用方式与使用Amino的私钥方法相同。
所有注册的对象均通过Amino使用4字节的PrefixBytes进行编码,该PrefixBytes标识唯一对象并包括有关其基础类型的信息。
接下来,我们直接提供类型名称和前缀字节。在对字节数组进行编码时,字节数组的长度将附加到PrefixBytes。因此,字节数组的编码变为  。因此,要编码下面列出的任何类型,无需熟悉氨基编码。您可以简单地使用下表并连接前缀||长度(原始字节数)||原始字节。


4.1 案例例如,将33字节(或十六进制的0x21字节)的Secp256k1公钥 020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9 编码为 EB5AE98721020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9 4.2 Key Types每种类型都指定其自己的pubkey,地址和签名格式。Ed25519TODO: pubkey该地址是原始32字节公共密钥中SHA256哈希值的前20个字节:



该签名是原始的64字节ED25519签名。
Sr25519TODO: pubkey该地址是原始32字节公共密钥中SHA256哈希值的前20个字节:



Secp256k1TODO: pubkey该地址是OpenSSL压缩公钥中SHA256哈希值里面的RIPEMD160哈希值:



这同比特币里面是一样的。

签名是ECDSA r和s(即r || s)的64字节级联,其中s在字典上小于其倒数,以防止延展性。这就像以太坊,但是没有用于恢复公钥的额外字节,因为Tendermint假定总是会提供公钥。 5  其他普通类型(other common types)
1)BitArray:在某些共识消息中使用BitArray表示从验证者那里收到的票数,或者在一个块中收到的部分票数。它用一个结构来表示,该结构包含位数(位)和以base64(Elems)编码的位数组本身。



这种类型很容易由Amino直接编码。


BitArray以x和_的形式接收表示1和0的特殊JSON编码。即BitArray 10110将被JSON编码为“ x_xx_” 2)Part:Part用于将块分解成碎片,这些碎片可以并行,并使用part的Merkle树节点进行安全验证。
Part包含索引(index)、Part的实际基础数据(bytes)以及Part包含在集合中的Merkle证明(proof)。


3)MakeParts:使用Amino方法将对象进行编码,并将其切成多个部分。Tendermint使用的part大小为65536字节,最多允许1601个parts。这对应100MB的硬编码块大小限制。



6  Merkle Trees

我们使用Merkle树的RFC 6962规范,并使用sha256作为哈希函数。在整个Tendermint中都使用Merkle树来计算数据结构的加密摘要。RFC 6962与最简单的merkle树之间的区别在于:


1)叶节点和内部节点具有不同的哈希值。这是为了“第二原像电阻”,以防止内部节点的证明作为叶节点的有效证明。叶节点为SHA256(0x00 || leaf_data),内部节点为SHA256(0x01 || left_hash || right_hash)。


2)当项目数不是2的幂时,树的左半部分会变得巨大。(2的最大幂数少于项目数)这可以花费更少的计算来添加新的叶节点。例如:


MerkleRoot:函数MerkleRoot是一个简单的递归函数,定义如下:



MerkleRoot对任意字节数组(不一定是哈希类型)进行操作。对于需要首先进行哈希处理的项目,我们引入了哈希函数:





我们将多次用到此概念,并使用struct类型或[] struct类型的参数调用MerkleRoot。对于结构参数,我们计算[][]的字节,其中包含该结构中每个字段的amino编码,其顺序与字段在结构中出现的顺序相同。对于[] struct自变量,我们通过对单个struct元素进行amino编码来计算[][]类型的字节。
Simple Merkle Proof:叶节点在Merkle树中的证明由以下组成:


验证如下:



aunts节点的数量限制为100(MaxAunts),以保护节点免受DOS攻击。这将树的大小限制为2 ^ 100个叶节点,这在任何情况下都应该足够。
IAVL+ Tree:由于Tendermint仅使用简单的Merkle树,因此应用程序开发人员应期望在其应用程序中使用自己的Merkle树。例如,Cosmos SDK使用了IAVL +树(一种用于保持应用程序状态的不可变的自平衡二进制树)。 7  JSON
Amino:Amino也支持JSON编码,注册类型可以简单地编码为:



例如,ED25519 PubKey便是:




其中“value”是原始pubkey字节的base64编码,而“ type”是Ed25519 pubkey的amino名称。
Signed Messages:使用Amino对共识中的签名消息(例如投票,提议)进行编码。
签名时,对消息的元素进行重新排序,因此固定长度字段位于第一位,从而可以轻松快速地检查类型、高度和圆周率。ChainID也附加到末尾。我们称这种编码为SignBytes。
例如,投票的SignBytes是以下结构的Amino编码:



以上代码对前三字段的排序和固定大小编码均进行了优化,以简化HSM中SignByte的解析。这为那些需要在上下文中进行读取活动的相关字段创建了固定的偏移量。


本文编译自Tendermint Spec, 来源:tendermint.com。










长按二维码关注我们


注:本文所使用的图片及音乐属于相关权利人所有,因客观原因,部分素材未能及时联系到相关权利人,如存在使用不当的情况,请相关权利人随时联系我们协商授权事宜。
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:173
帖子:4
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP