原文: https://www.cnblogs.com/yimeixiaobai1314/p/14359395.html
前言
最近在搞區塊鏈瀏覽器,也就是通過網頁來查看Fabric區塊鏈的各項信息,主要包含區塊、交易、鏈碼、節點信息等等。這些信息主要來源於從Fabric中獲取的區塊JSON數據。因為網上關於Fabric區塊鏈的各項資料不是很多,故而自己整理了一份簡略的資料。同時也希望這份資料能幫助到大家。
區塊結構介紹
區塊鏈中的區塊結構一般分為區塊頭和區塊體兩部分,但是Fabric區塊的數據結構分為三大部分:Header
(區塊頭)、Data
(區塊體,包含所有的交易信息)、MetaData
(和當前區塊相關的元數據)。區塊數據結構如下:
type Block struct {
Header *BlockHeader,
Data *BlockData,
MetaData *BlockMetaData
}
以下三張圖來源於網絡以及其他博客,第一張是英文版的區塊結構圖,第二張是中文版的區塊結構圖,第三張是整個區塊數據結構的分解圖,僅供大家參考。
英文版:
中文版:
區塊數據結構:
下面提供一個區塊json數據供大家分析。
{
"header": {
"number": "14",
"previous_hash": "057935b395be9d6757f61a62eea2fd5c37e7089f3c991a7a9a131aefb255d450",
"data_hash": "39ba8f0e54e75980414b301a343f42981ba63f8f105cd72d0e039010843aa920"
},
"data": {
"data": [{
"signature": {
"type": "Buffer",
"data": [48, 68, 2, 32, 53, 212, 86, 141, 134, 170, 144, 75, 132, 68, 229, 103, 122, 240, 21, 201, 139, 191, 77, 193, 50, 192, 31, 9, 15, 187, 65, 112, 239, 36, 205, 182, 2, 32, 98, 217, 249, 62, 93, 24, 158, 247, 180, 186, 122, 237, 141, 54, 228, 20, 218, 234, 24, 246, 118, 205, 134, 187, 250, 198, 255, 79, 129, 159, 164, 220]
},
"payload": {
"header": {
"channel_header": {
"type": 3,
"version": 1,
"timestamp": "2021-01-10T12:01:29.673Z",
"channel_id": "common",
"tx_id": "ff28b4847400b16742245590d908b57a3643e4cc62baf3264dd8751070342314",
"epoch": "0",
"extension": {
"type": "Buffer",
"data": [18, 11, 18, 9, 99, 104, 97, 105, 110, 99, 111, 100, 101]
},
"typeString": "ENDORSER_TRANSACTION"
},
"signature_header": {
"creator": {
"Mspid": "org1",
"IdBytes": "-----BEGIN CERTIFICATE-----\nMIICcTCCAhegAwIBAgIUbtNpC7qvKr1n5OxgOZiaBRu2VtgwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjEwMTEwMTE1NjAwWhcNMjIwMTEwMTIw\nMTAwWjAvMRwwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMQ8wDQYDVQQDEwZh\nZG1pbjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASlFdeOOyJRw4/25L62W/KA\nmYpCFsV0CwnezSVEuJL44vC0vqpYUlk1CdR1UO8bkcutgBHXsly+gWyH+GZtSD59X\no4HMMIHJMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSu\nKGe8YTCjfa0+f+l0Q6Woq+S94zArBgNVHSMEJDAigCA2OH3OJFJR5m75pJceBgqt\ni7zg18hHdCVIjZOnvoUxazBdBggqAwQFBgcIAQRReyJhdHRycyI6eyJoZi5BZmZp\nbGlhdGlvbiI6Im9yZzEiLCJoZi5FbnJvbGxtZW50SUQiOiJhZG1pbjEiLCJoZi5U\neXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCiNYmu/NaH/pBStOZf\nfa2OcoTmBsJvztFikt/+CGjZ0gIgUJd1Ay3vi1V/WNMoAxr/3uA84qwAP0TRwcQw\nIjyEzZA=\n-----END CERTIFICATE-----\n"
},
"nonce": {
"type": "Buffer",
"data": [217, 120, 226, 190, 89, 228, 29, 80, 164, 122, 27, 114, 128, 137, 117, 209, 53, 235, 81, 90, 147, 12, 11, 218]
}
}
},
"data": {
"actions": [{
"header": {
"creator": {
"Mspid": "org1",
"IdBytes": "-----BEGIN CERTIFICATE-----\nMIICcTCCAhegAwIBAgIUbtNpC7qvKr1n5OxgOZiaBRu2VtgwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjEwMTEwMTE1NjAwWhcNMjIwMTEwMTIw\nMTAwWjAvMRwwDQYDVQQLEwZj1bGllbnQwCwYDVQQLEwRvcmcxMQ8wDQYDVQQDEwZh\nZG1pbjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASlFdeOOyJRw4/25L62W/KA\nmYpCFsV0CwnezSVEuJL44vC0vqpYUlk1CdRUO8bkcutgBHXsly+gWyH+GZtSD59X\no4HMMIHJMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSu\nKGe8YTCjfa0+f+l0Q6Woq+S94zArBgNVHSMEJDAigCA2OH3OJFJR5m75pJceBgqt\ni7zg18hHdCVIjZOnvoUxazBdBggqAwQFBgcIAQRReyJhdHRycyI6eyJoZi5BZmZp\nbGlhdGlvbiI6Im9yZzEiLCJoZi5FbnJvbGxtZW50SUQiOiJhZG1pbjEiLCJoZi5U\neXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCiNYmu/NaH/pBStOZf\nfa2OcoTmBsJvztFikt/+CGjZ0gIgUJd1Ay3vi1V/WNMoAxr/3uA84qwAP0TRwcQw\nIjyEzZA=\n-----END CERTIFICATE-----\n"
},
"nonce": {
"type": "Buffer",
"data": [217, 120, 226, 190, 89, 228, 29, 80, 164, 122, 27, 114, 128, 137, 117, 209, 53, 235, 81, 90, 147, 12, 11, 218]
}
},
"payload": {
"chaincode_proposal_payload": {
"input": {
"chaincode_spec": {
"type": 1,
"typeString": "GOLANG",
"input": {
"args": [{
"type": "Buffer",
"data": [112, 117, 116]
}, {
"type": "Buffer",
"data": [123, 34, 117, 115, 101, 114, 110, 97, 109, 101, 34, 12, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 34, 97, 99, 116, 105, 111, 110, 34, 58, 34, 115, 116, 111, 114, 101, 34, 44, 34, 109, 111, 110, 101, 121, 34, 58, 34, 50, 48, 48, 34, 125]
}],
"decorations": {}
},
"chaincode_id": {
"path": "",
"name": "chaincode",
"version": ""
},
"timeout": 0
}
}
},
"action": {
"proposal_response_payload": {
"proposal_hash": "932fb85e4b503cfdf2efbd8b9f45df5240da040cacd4c7970659263633c3afc3",
"extension": {
"results": {
"data_model": 0,
"ns_rwset": [{
"namespace": "chaincode",
"rwset": {
"reads": [],
"range_queries_info": [],
"writes": [{
"key": "\u0000neil\u0000store\u0000200\u0000",
"is_delete": false,
"value": "{\"username\":\"neil\",\"action\":\"store\",\"money\":\"200\"}"
}],
"metadata_writes": []
},
"collection_hashed_rwset": []
}, {
"namespace": "lscc",
"rwset": {
"reads": [{
"key": "chaincode",
"version": {
"block_num": "5",
"tx_num": "0"
}
}],
"range_queries_info": [],
"writes": [],
"metadata_writes": []
},
"collection_hashed_rwset": []
}]
},
"events": {
"chaincode_id": "",
"tx_id": "",
"event_name": "",
"payload": {
"type": "Buffer",
"data": []
}
},
"response": {
"status": 200,
"message": "",
"payload": ""
},
"chaincode_id": {
"path": "",
"name": "chaincode",
"version": "1.0"
}
}
},
"endorsements": [{
"endorser": {
"Mspid": "org1",
"IdBytes": "-----BEGIN CERTIFICATE-----\nMIICGTCCAcCgAwIBAgIRAP5eKKLGhfTuzLVPIrPcbTwwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjEwMTEwMTA1NTAwWhcNMzEwMTA4MTA1NTAw\nWjBbMQswCQ1YDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEfMB0GA1UEAxMWcGVlcjAub3JnMS5leGFtcGxlLmNvbTBZ\nMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFo3HMBdd10LjYeZwMtR59Byjjp11pd8\nlvWaItRsbrwDvAugdGDZ3KC1FVHLhblCbFp4sDyRDPwJIDnXYIZUpFWjTTBLMA4G\nA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIDY4fc4kUlHm\nbvmklx4GCq2LvODXyEd0JUiNk6e+hTFrMAoGCCqGSM49BAMCA0cAMEQCIE0PYDKu\ncPYusfTbqem0AwtrqMx/2kUSP9X6/HA5en0lAiB/YePKYDu91h336nNcxal98vNB\nPKyoL+zVCRqL/MYvCQ==\n-----END CERTIFICATE-----\n"
},
"signature": {
"type": "Buffer",
"data": [48, 68, 2, 32, 14, 77, 226, 146, 105, 55, 164, 194, 11, 71, 51, 147, 63, 74, 207, 104, 106, 187, 117, 175, 187, 194, 244, 165, 25, 132, 52, 8, 190, 217, 81, 46, 2, 32, 22, 123, 212, 121, 242, 138, 121, 213, 55, 113, 46, 11, 23, 119, 148, 62, 172, 83, 199, 24, 133, 151, 60, 144, 177, 255, 65, 182, 177, 225, 0, 222]
}
}]
}
}
}]
}
}
}]
},
"metadata": {
"metadata": [{
"value": "\n\u0002\b\u0003",
"signatures": [{
"signature_header": {
"creator": {
"Mspid": "orderer.example.com",
"IdBytes": "-----BEGIN CERTIFICATE-----\nMIICDTCCAbOgAwIBAgIRAKZzKwIm1fXv9TbfsLSlJpUwCgYIKoZIzj0EAwIwaTEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRcwFQYDVQQDEw5jYS5leGFt\ncGxlLmNvbTAeFw0yMTAxMTAxMDU1MDBaFw0zMTAxMDgxMDU1MDBaMFgxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMRwwGgYDVQQDExNvcmRlcmVyLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYI\nKoZIzj0DAQcDQgAEYh4Kui3YB02J9uUjX7+nn+l5ZT6DFWXjhB6X3fjUjowvySzf\nfqn4s95o6qc0jYCaiC47cfUlJKvlPsBQX8XzyKNNMEswDgYDVR0PAQH/BAQDAgeA\nMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAg1HCS4tEmcKJX2ttGPCY4mw2VSA5lP\nkVeYrnAulge4U0gwCgYIKoZIzj0EAwIDSAAwRQIhAJQom8NqJdKvG3uYkbcuFRbx\nUxVltC+/OdqLZ2ByCVWzAiAv0mGOCKPogI1QZdowWXsHtS9bZw3ymtwVToLXI+zP\nzg==\n-----END CERTIFICATE-----\n"
},
"nonce": {
"type": "Buffer",
"data": [32, 137, 232, 144, 240, 168, 86, 24, 236, 47, 151, 23, 182, 223, 129, 176, 92, 209, 74, 104, 78, 83, 86, 125]
}
},
"signature": {
"type": "Buffer",
"data": [48, 69, 2, 33, 0, 159, 188, 112, 227, 84, 54, 225, 211, 227, 157, 120, 16, 218, 64, 137, 137, 94, 9, 217, 83, 249, 31, 24, 66, 75, 78, 14, 219, 182, 220, 75, 223, 2, 32, 106, 39, 131, 38, 77, 200, 222, 147, 195, 62, 173, 63, 254, 133, 174, 73, 161, 75, 40, 248, 173, 62, 83, 56, 141, 99, 162, 94, 181, 72, 68, 188]
}
}]
}, {
"value": {
"index": "3"
},
"signatures": []
},
[0]
]
}
}
大家可以通過在線json解析工具對json數據進行層次解析后再查看,這樣會更加方便。我下面的對具體數據結構以及字段的分析和講解也會依賴於這個解析工具的部分截圖。
整個區塊結構如下圖所示:
Block Header部分
區塊頭包含三個字段,
number
(當前區塊號)、previous_hash
(前一個區塊頭哈希)、data_hash
(當前區塊的數據哈希)。值得一提的是
data_hash
並非當前區塊哈希,只是當前區塊數據體的哈希值,大家在呈現區塊數據時要注意這一點。
type BlockHeader struct {
Number uint64
PreviousHash []byte
DataHash []byte
}
Block Data部分
區塊體中只有一個
data
字段,data
字段對應的屬性值中也只有一個data
字段。這個data
字段對應是Envelope
數據,即一種展示交易信息的數據結構,具體看下面的JSON信息截圖。
Envelope數據
此數據類型主要用於存儲區塊中的交易信息。交易信息包括兩個字段,
signature
(交易發送者的簽名)、payload
(數據載荷)(具體看上方截圖和下面的數據類型)。signature
是一個buffer數組類型的簽名數據,並無其他可用信息,故下面主要分析payload
數據載荷字段部分。
type Envelope struct {
Payload []byte
Signature []byte
}
Envelope.payload字段
Palyload
中包含了Header
和Data
兩個字段,其中Header中又包含了ChannelHeader
和SignatureHeader
。具體看下面的數據結構及JSON信息截圖。
type Payload struct {
Header *Header
Data []byte
}
type Header struct {
ChannelHeader *ChannelHeader,
SignatureHeader *SignatureHeader
}
-
channelHeader
channelHeader
數據包括type
(頭類型)、version
(版本)、timestamp
(時間戳,即交易產生時間)、channel_id
(通道id)、tx_id
(交易id,即交易哈希)、epoch
(時期,該字段當前未使用)、extension
(可附加的擴展)、typeString
(類型字符串,主要包括MESSAGE、CONFIG(表示當前塊為區塊鏈配置塊)、CONFIG_UPDATE、ENDORSER_TRANSACTION(表示當前塊為區塊鏈正常交易塊,大多數區塊都為此類型)、ORDERER_TRANSACTION、DELIVER_SEEK_INFO、CHAINCODE_PACKAGE等類型)。 -
SignatureHeader
SignatureHeader
數據包括creator
(交易創建者的信息,具體的peer節點信息好像可以通過解析證書來實現,但我還未實現,有已經實現的朋友可以在下面留言告訴我,謝謝大家!)、nonce
(隨機數),其中creator
包括創建者的證書和Mspid
(成員服務提供者的身份證書)。
Envelope.payload.data字段
data
包含一個actions
字段,對應的值是一個action數組,每個數組又包含兩部分,header
和payload
。header
結構都與上面解析過的signature_header
相同(目前未搞懂fabric設計者的做此舉目的),下面主要討論payload
字段部分。
Envelope.payload.data.actions.payload字段
payload
字段包括chaincode_proposal_payload
(背書提案時調用鏈碼的信息)和action
字段,action
字段又分為proposal_response_payload
(提案時響應信息,也就是是不是提案成功了,成功了返回狀態碼為200)及endorsements
(背書節點信息)字段。
下面具體分析chaincode_proposal_payload
與proposal_response_payload
兩個字段:
-
chaincode_proposal_payload
chaincode_proposal_payload
具體結構參見上面的截圖。chaincode_proposal_payload
含有一個input
字段,該字段中又包含chaincode_spec
字段。chaincode_spec
字段包含鏈碼信息和調用期間使用的參數。type
是鏈碼類型,typeString
是鏈碼使用的語言,input
是使用鏈碼的參數,decoration
字段含義未知(中文含義為裝飾物),但對應的值一般為空。chaincode_id
字段包含鏈碼的路徑、名稱和版本信息。最后具體說一下
input
字段,它包含一個args
數組,數組中含有兩個元素,第一個元素是調用鏈碼的函數名,第二個是函數參數,都為buffer數組,大家可以通過將buffer轉換為string來獲取到原數據。 -
proposal_response_payload
proposal_response_payload
字段包含鏈碼模擬執行結果對KV類型狀態數據庫的讀寫集,包括proposal_hash
(背書哈希值)、results
(背書結果)、response
(背書響應)、chaincode_id
(鏈碼信息)。results
包含data_model
(數據模型,但含義未知,一般為0)、ns_rwset
(讀寫集數組)。ns_rwset
包含namespace
、rwset
。rwset
包含read
(讀集)、writes
(寫集,包含鍵、值、刪除標志)、range_queries_info
(范圍查詢信息)、metadata_writes
。response
包含status
(響應狀態值)、message
(響應信息)、payload
(返回的數據,一般是查詢時采用此字段)。 -
endorsements
該字段包含背書者信息數組,每個背書者包含
MspId
、證書和此次背書的簽名signature
。此結構比較簡單,就不展開具體分析。大家有需要可以自己通過在線json解析工具進行查看。
Block MetaData部分
元數據:和當前區塊相關的元數據,用於描述Data的相關信息,包含排序節點的MspId、證書和隨機數,以及簽名。value的index屬性及一些其他的字段含義也不太清楚,但是這些信息大多是空值並且與區塊鏈相關狀態信息並不相關,故並未仔細分析。數據結構如下:
type BlockMetadata struct {
Metadata [][]byte
}
結語
上面的信息基本可以滿足做區塊鏈瀏覽器的需要了,但是還是缺少一部分信息,比如區塊產生時間等等。目前我是以區塊中最后一個交易的產生時間來作為區塊產生時間的,這在嚴格意義上來說是不對,因為產生最后一個交易后需要經過Orderer節點的排序、打包等操作才能產生區塊。
最后衷心希望上述信息能給大家帶來幫助!
本博客中部分信息參考於:https://blog.csdn.net/alextan_/article/details/110826476
在此感謝此博客的作者!
type ChannelHeader struct {
Type int32
Version int32
Timestamp *google_protobuf.Timestamp
ChannelId string
TxId string
Epoch uint64
Extension []byte
}
/*
Type: It denotes the transaction type used. ["MESSAGE", "CONFIG", "CONFIG_UPDATE", "ENDORSER_TRANSACTION",
"ORDERER_TRANSACTION", "DELIVER_SEEK_INFO", "CHAINCODE_PACKAGE"]
Version: The version number for protobuf used for serialization/de-serialization of the structures.
ChannelId: Channel name for the network
TxId: The transaction id for processing the transaction
Epoch: The fields are currently unused.
Extension: It contents Chaincode information that marshalled the ChaincodeHeaderExtension structure.
*/
https://blog.csdn.net/AlexTan_/article/details/110826476
type ChaincodeHeaderExtension struct { // The PayloadVisibility field controls to what extent the Proposal's payload // (recall that for the type CHAINCODE, it is ChaincodeProposalPayload // message) field will be visible in the final transaction and in the ledger. // Ideally, it would be configurable, supporting at least 3 main visibility // modes: // 1. all bytes of the payload are visible; // 2. only a hash of the payload is visible; // 3. nothing is visible. // Notice that the visibility function may be potentially part of the ESCC. // In that case it overrides PayloadVisibility field. Finally notice that // this field impacts the content of ProposalResponsePayload.proposalHash. PayloadVisibility []byte `protobuf:"bytes,1,opt,name=payload_visibility,json=payloadVisibility,proto3" json:"payload_visibility,omitempty"` // The ID of the chaincode to target. ChaincodeId *ChaincodeID `protobuf:"bytes,2,opt,name=chaincode_id,json=chaincodeId,proto3" json:"chaincode_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
https://pkg.go.dev/github.com/hyperledger/fabric/protos/peer#ChaincodeHeaderExtension
Fabric 2.2底層結構設計分析
https://www.cnblogs.com/veraland/p/13900791.html