【区块链】Tendermint——实体结构
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 []TxTx又是什么呢,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 []byteLastCommit
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——实体结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杰理之使用G版芯片替换生产时【篇】
- 下一篇: 简单的设计