Fabric Block区块结构解析

Fabric Block区块结构解析

作者: AlexTan

CSDN: http://blog.csdn.net/alextan_

Github: https://github.com/AlexTan-b-z

e-mail: alextanbz@gmail.com

前言

最近自己在用Fabric-sdk-go写区块链浏览器,真的觉得Golang作为Hyperledger Fabric的亲儿子语言,但对SDK的支持极不友好,可以说Fabric-sdk-go几乎没有文档,更多的只能查看源码中的测试用例来使用,而对于测试用例来说,想完成区块链浏览器的需求,还很不够,特别是对Fabric本身的区块及交易的数据结构的解析是完全没有的,比如说:

在获取区块的的测试用例中就返回了一个*common.Block结构,而如何处理这个Block,是完全没有的。

而网上对Fabric的区块结构解析有部分内容还是错的,因此这里写一篇博客来帮助大家避免踩坑。

区块结构图

以下两张图是网上找的,第一张图是区块的结构,第二张图是数据结构的定义图,两张图配合看。不过,请注意,我在使用当中发现第二张图数据结构的定义图有部分内容是错误的,不知道是不是版本原因,我用的是1.4.6版本,比如说:

SignatureHeader下的signingidentity应该是SerializedIdentity

不知道画图的大神是用的什么版本的Fabric,因此图片仅供大家酌情参考。

好了,废话不多说,放图:
在这里插入图片描述
在这里插入图片描述

完全解析后的区块数据

{
    "data": {
        "data": {
            "data": [
                {
                    "payload": {
                        "data": {
                            "actions": [
                                {
                                    "header": {
                                        "creator": {
                                            "id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLekNDQWRHZ0F3SUJBZ0lSQUxrUEVNZ1lEZ0lxaXJRMXdtM1ZkaWt3Q2dZSUtvRWN6MVVCZzNVd2N6RUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhHVEFYQmdOVkJBb1RFRzl5WnpFdVpYaGhiWEJzWlM1amIyMHhIREFhQmdOVkJBTVRFMk5oCkxtOXlaekV1WlhoaGJYQnNaUzVqYjIwd0hoY05NakF4TVRFek1USXdNREV6V2hjTk16QXhNVEV4TVRJd01ERXoKV2pCc01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQk1LUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnhNTgpVMkZ1SUVaeVlXNWphWE5qYnpFUE1BMEdBMVVFQ3hNR1kyeHBaVzUwTVI4d0hRWURWUVFEREJaVmMyVnlNVUJ2CmNtY3hMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb0VjejFVQmdpMERRZ0FFN0Qza0VDUTAKVUYweUhmQVFsTyt0bEVKT0MzdVU4c0tlTDM4N1NkTjhNMkZLSE9sZmNJSkVPVWhUeUtDMmtUQUpWMzZpTUlhdAo4V2JHMVN2S1ZBcWZTYU5OTUVzd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEClZSMGpCQ1F3SW9BZ25pbmsvSWF2UW0yWXJ0cXAyMThZVjFvdXlHem1aZzNEUjBiR3Ezd1VvenN3Q2dZSUtvRWMKejFVQmczVURTQUF3UlFJaEFJeldmZ2NUTVJ4WE5rT1NlSmRoTFNnRmQ1NnU4WkFQS1EvVk9JN2kxeEd5QWlBcAozSituSVZQaFo4QlFSMFdadmJIYUFjN3VKWWRFVXVuYndJUUk0Z1o4YkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
                                            "mspid": "Org1MSP"
                                        },
                                        "nonce": "UIsr0CSC/gLmpdMZDnDmN3pR/T53NH5q"
                                    },
                                    "payload": {
                                        "action": {
                                            "endorsements": [
                                                {
                                                    "endorser": "CgdPcmcxTVNQEqYGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNKakNDQWM2Z0F3SUJBZ0lRSXhGc2RKSDJra0FPSk9lbkJTSjJBekFLQmdncWdSelBWUUdEZFRCek1Rc3cKQ1FZRFZRUUdFd0pWVXpFVE1CRUdBMVVFQ0JNS1EyRnNhV1p2Y201cFlURVdNQlFHQTFVRUJ4TU5VMkZ1SUVaeQpZVzVqYVhOamJ6RVpNQmNHQTFVRUNoTVFiM0puTVM1bGVHRnRjR3hsTG1OdmJURWNNQm9HQTFVRUF4TVRZMkV1CmIzSm5NUzVsZUdGdGNHeGxMbU52YlRBZUZ3MHlNREV4TVRNeE1qQXdNVE5hRncwek1ERXhNVEV4TWpBd01UTmEKTUdveEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTVJZd0ZBWURWUVFIRXcxVApZVzRnUm5KaGJtTnBjMk52TVEwd0N3WURWUVFMRXdSd1pXVnlNUjh3SFFZRFZRUURFeFp3WldWeU1DNXZjbWN4CkxtVjRZVzF3YkdVdVkyOXRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvRWN6MVVCZ2kwRFFnQUVpVFNRNWVFZU0vancKQkU5UDJJRlh6a3VWVlRKbHI0dnA4NGJ3L3E5V3ZIZzg1NDJSZ0xGa3pNVmllcXY1OEtKRkFyL1MzL1NoNy9naApJN3hmWUJjTmhLTk5NRXN3RGdZRFZSMFBBUUgvQkFRREFnZUFNQXdHQTFVZEV3RUIvd1FDTUFBd0t3WURWUjBqCkJDUXdJb0Fnbmluay9JYXZRbTJZcnRxcDIxOFlWMW91eUd6bVpnM0RSMGJHcTN3VW96c3dDZ1lJS29FY3oxVUIKZzNVRFJnQXdRd0lmUXdwR0FvaWlleUw3R2IyM1FwS2JGYk9GMkZBSWZ2bWhiZ0hIMGgrRHJnSWdUc1hIVGU4VApZNnkxLzVtNW1kcXUzcVMxSTJyZFNhQjhsRTBEZGpEOWxVcz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=",
                                                    "signature": "MEUCIHKOMG//auILmgI7qEehkWjjwZZmnLOQjf+KXeS/3rUwAiEA1BUOnwyJjT6npM9C9UIdaORnkXH0/QTkdu6oR0nuRr8="
                                                }
                                            ],
                                            "proposal_response_payload": {
                                                "extension": {
                                                    "chaincode_id": {
                                                        "name": "mycc",
                                                        "path": "",
                                                        "version": "v1"
                                                    },
                                                    "events": {
                                                        "chaincode_id": "mycc",
                                                        "event_name": "addCredit",
                                                        "payload": null,
                                                        "tx_id": "93828232e69cc0614ced9001c06b586c3ccc56ce42c23a3528472c1ed00c9748"
                                                    },
                                                    "response": {
                                                        "message": "",
                                                        "payload": "5L+h5oGv5re75Yqg5oiQ5Yqf",
                                                        "status": 200
                                                    },
                                                    "results": {
                                                        "data_model": "KV",
                                                        "ns_rwset": [
                                                            {
                                                                "collection_hashed_rwset": [],
                                                                "namespace": "lscc",
                                                                "rwset": {
                                                                    "metadata_writes": [],
                                                                    "range_queries_info": [],
                                                                    "reads": [
                                                                        {
                                                                            "key": "mycc",
                                                                            "version": {
                                                                                "block_num": "1",
                                                                                "tx_num": "0"
                                                                            }
                                                                        }
                                                                    ],
                                                                    "writes": []
                                                                }
                                                            },
                                                            {
                                                                "collection_hashed_rwset": [],
                                                                "namespace": "mycc",
                                                                "rwset": {
                                                                    "metadata_writes": [],
                                                                    "range_queries_info": [],
                                                                    "reads": [
                                                                        {
                                                                            "key": "test3",
                                                                            "version": null
                                                                        }
                                                                    ],
                                                                    "writes": [
                                                                        {
                                                                            "is_delete": false,
                                                                            "key": "test3",
                                                                            "value": "eyJkb2NUeXBlIjoiQ3JlZGl0T2JqIiwiWnhIYXNoIjoiYWUyYzdkNjUyZTc2ZTU3NjcxZjhmZjA1OGQxOTliODU3OGEyNzJmZWY1NmM3ZWRiMTVjZjllODM3ODkzMGM5NyIsIk9wZXJhdG9yIjoi5rWL6K+VMSIsIlRpbWUiOiIyMDIwLTEyLTAzIDEyOjIyOjAzIiwiUGRmSWQiOiJ0ZXN0MyIsInNhdmVfcGF0aCI6IiIsInNxbF92YWx1ZSI6eyLkv6HnlKjor4TnuqciOiJBIiwi5b6X5YiGIjoiMTAifSwiSGlzdG9yaWVzIjpudWxsfQ=="
                                                                        }
                                                                    ]
                                                                }
                                                            }
                                                        ]
                                                    }
                                                },
                                                "proposal_hash": "aNwzCaemR8oP8MG/74cCpDa0G1ekmrBOl5wCZ8tawaU="
                                            }
                                        },
                                        "chaincode_proposal_payload": {
                                            "TransientMap": {},
                                            "input": {
                                                "chaincode_spec": {
                                                    "chaincode_id": {
                                                        "name": "mycc",
                                                        "path": "",
                                                        "version": ""
                                                    },
                                                    "input": {
                                                        "args": [
                                                            "YWRkQ3JlZGl0",
                                                            "eyJkb2NUeXBlIjoiIiwiWnhIYXNoIjoiYWUyYzdkNjUyZTc2ZTU3NjcxZjhmZjA1OGQxOTliODU3OGEyNzJmZWY1NmM3ZWRiMTVjZjllODM3ODkzMGM5NyIsIk9wZXJhdG9yIjoi5rWL6K+VMSIsIlRpbWUiOiIyMDIwLTEyLTAzIDEyOjIyOjAzIiwiUGRmSWQiOiJ0ZXN0MyIsInNhdmVfcGF0aCI6IiIsInNxbF92YWx1ZSI6eyLkv6HnlKjor4TnuqciOiJBIiwi5b6X5YiGIjoiMTAifSwiSGlzdG9yaWVzIjpudWxsfQ=="
                                                        ],
                                                        "decorations": {},
                                                        "is_init": false
                                                    },
                                                    "timeout": 0,
                                                    "type": "UNDEFINED"
                                                }
                                            }
                                        }
                                    }
                                }
                            ]
                        },
                        "header": {
                            "channel_header": {
                                "channel_id": "mychannel",
                                "epoch": "0",
                                "extension": {
                                    "chaincode_id": {
                                        "name": "mycc",
                                        "path": "",
                                        "version": ""
                                    }
                                },
                                "timestamp": "2020-12-03T12:22:03.799607788Z",
                                "tls_cert_hash": null,
                                "tx_id": "93828232e69cc0614ced9001c06b586c3ccc56ce42c23a3528472c1ed00c9748",
                                "type": 3,
                                "version": 0
                            },
                            "signature_header": {
                                "creator": {
                                    "id_bytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLekNDQWRHZ0F3SUJBZ0lSQUxrUEVNZ1lEZ0lxaXJRMXdtM1ZkaWt3Q2dZSUtvRWN6MVVCZzNVd2N6RUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhHVEFYQmdOVkJBb1RFRzl5WnpFdVpYaGhiWEJzWlM1amIyMHhIREFhQmdOVkJBTVRFMk5oCkxtOXlaekV1WlhoaGJYQnNaUzVqYjIwd0hoY05NakF4TVRFek1USXdNREV6V2hjTk16QXhNVEV4TVRJd01ERXoKV2pCc01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQk1LUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnhNTgpVMkZ1SUVaeVlXNWphWE5qYnpFUE1BMEdBMVVFQ3hNR1kyeHBaVzUwTVI4d0hRWURWUVFEREJaVmMyVnlNVUJ2CmNtY3hMbVY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb0VjejFVQmdpMERRZ0FFN0Qza0VDUTAKVUYweUhmQVFsTyt0bEVKT0MzdVU4c0tlTDM4N1NkTjhNMkZLSE9sZmNJSkVPVWhUeUtDMmtUQUpWMzZpTUlhdAo4V2JHMVN2S1ZBcWZTYU5OTUVzd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3R0ExVWRFd0VCL3dRQ01BQXdLd1lEClZSMGpCQ1F3SW9BZ25pbmsvSWF2UW0yWXJ0cXAyMThZVjFvdXlHem1aZzNEUjBiR3Ezd1VvenN3Q2dZSUtvRWMKejFVQmczVURTQUF3UlFJaEFJeldmZ2NUTVJ4WE5rT1NlSmRoTFNnRmQ1NnU4WkFQS1EvVk9JN2kxeEd5QWlBcAozSituSVZQaFo4QlFSMFdadmJIYUFjN3VKWWRFVXVuYndJUUk0Z1o4YkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
                                    "mspid": "Org1MSP"
                                },
                                "nonce": "UIsr0CSC/gLmpdMZDnDmN3pR/T53NH5q"
                            }
                        }
                    },
                    "signature": "MEYCIQCei8fnd77l3iL0RY2wVwy6SxcM2MK9GWYV/GwbSEFSHAIhAJDqh8BhDczPnbcY0yhfNZ2bI9i7z9V9xl+zdPL9QUJk"
                }
            ]
        },
        "header": {
            "data_hash": "QR8c9tG83W4/8+4jl8W15GPGhV5a8gOhWgFLWpqPUMY=",
            "number": "6",
            "previous_hash": "ZsUXUM2pphlG/CxdUzFdIvwF38ioc3UEBSbPeae0e8s="
        },
        "metadata": {
            "metadata": [
                "Cg8KABILCgkKAwECAxAEGAoSlwcKygYKrQYKCk9yZGVyZXJNU1ASngYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ0lEQ0NBY2FnQXdJQkFnSVJBUGFPN1pkZ0I4Z0UyZ2wzWkFLNHJtOHdDZ1lJS29FY3oxVUJnM1V3YVRFTApNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdUQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjVERWTmhiaUJHCmNtRnVZMmx6WTI4eEZEQVNCZ05WQkFvVEMyVjRZVzF3YkdVdVkyOXRNUmN3RlFZRFZRUURFdzVqWVM1bGVHRnQKY0d4bExtTnZiVEFlRncweU1ERXhNVE14TWpBd01UTmFGdzB6TURFeE1URXhNakF3TVROYU1Hc3hDekFKQmdOVgpCQVlUQWxWVE1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGhNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wCmMyTnZNUkF3RGdZRFZRUUxFd2R2Y21SbGNtVnlNUjB3R3dZRFZRUURFeFJ2Y21SbGNtVnlNaTVsZUdGdGNHeGwKTG1OdmJUQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxQkhNOVZBWUl0QTBJQUJKS2hJazQ5MlVRU2w1WmdVQVN1RlJUZApZOVpVZEpPQ2hBU2E2U2Qxc1VWUjd5QWVzcDY4bUFzQVQ3VGZib3B2UzdjeGpHRm9jYkloSkZjK1liaVBTdENqClRUQkxNQTRHQTFVZER3RUIvd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUNzR0ExVWRJd1FrTUNLQUlFT0MKYWRIY1ZoaHhZS1dUMEl6RUtaZmhBMmtpQkNrS0RuZmJhVXJaSWJ4cE1Bb0dDQ3FCSE05VkFZTjFBMGdBTUVVQwpJQis5WGY5V25la0R6aFlNNnk3dUwrZ0pMMlZtcTN1TEMrQjBmMk1vUnFXMUFpRUE5MFd5UGd2THEvVDI4Q3JLClZYaDdxWFV2dXQwTkZScVRSTEpYMW03U2VZYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSGCYqepNKdDjThpB0OuphLSYvkJ4FtxNMlxJIMEYCIQClr0fyIVcE7eHjE5Z+2KFJpKf8uHtyyKt9Skf3PyFnawIhAKp3PJJxc3NQUBNgnzp2Jwtr0Ycgg7S+IbHU7OSzAeQR",
                "",
                "AA==",
                "CgkKAwECAxAEGAo=",
                "CiDRjMKMZ4dC+S+zBfjclXL4PUxnyvJaVbXSZSavufdfrg=="
            ]
        }
    },
    "msg": "Get block success",
    "status": 1
}

很明显,这个数据并不是我们想要的数据,里面有太多的[]byte和一堆对区块链浏览器而言无用的字段,而如何解析这些字段,请看下面内容。

注意:建议在做解析字段时结合json数据和图片看

解析区块数据

接下来,我将演示用Go来提取Hyperledger Fabric中块结构的各个部分。

先来看数据结构:

Block

众所周知,区块结构一般分为区块头和body两部分(除此之外还有其他的一些配置数据),Fabric也不例外,Header为Fabric的区块头,Data为Fabric的Body。

type Block struct {
	    Header   *BlockHeader   
	    Data     *BlockData     
	    Metadata *BlockMetadata 
	}

BlockHeader

区块头所包含的信息和bitcoin差不多,包含了区块序列号、前一个区块的哈希和当前区块数据(所有交易)的哈希。注意:DataHash并不是当前区块哈希,当前区块哈希的计算方式为区块头的三个字段(即number、previous_hash、data_hash)首先使用ASN.1中的DER编码规则进行编码,而后进行SHA256哈希值计算得出。

type BlockHeader struct {
	    Number   	    uint64
	    PreviousHash    []byte
	    DataHash        []byte
}

BlockData

区块Body中只有一个Data字段,它是一个字节数组类型,可以用common.Envelope来解析,Envelope就是一个比较复杂的数据类型了。

type BlockData struct {
     Data [][]byte 
}

BlockMetaData

MetaData字段包含块的创建时间,证书详细信息和块编写器的签名。这个字段在区块链浏览器中一般用不到,在这里就不做详细解析了。

type BlockMetadata struct {
  Metadata   [][]byte
}

Envelope

提取区块中的交易数据就得从此数据结构开始。

type Envelope struct {
     Payload   []byte 
     Signature []byte
}
从BlockData中获取Envelope
func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error){
	var err error
	env := &common.Envelope{}
	if err = proto.Unmarshal(data, env); err != nil {
		return nil, errors.Wrap(err, "error unmarshaling Envelope")
	}

	return env, nil
}

Payload

从完全解析成json后的区块数据中可以看出,Palyload中包含了HeaderData两个变量,其中Header中包含了ChannelHeaderSignatureHeader

type Payload struct {
     Header *Header 
     Data   []byte 
}
从Envelop中获取Payload
payload := &common.Payload{}
err = proto.Unmarshal(envelope.Payload, payload)
if err != nil {
   return errors.WithMessage(err,"unmarshaling Payload error: ")
}

Payload Header

ChannelHeader

包含了channel信息和链码信息

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.

*/
从Payload中获取ChannelHeader
channelHeader := &common.ChannelHeader{}
err := proto.Unmarshal(payload.Header.ChannelHeader, channelHeader)
if err != nil {
	return ChannelHeader{}, errors.WithMessage(err,"unmarshaling Channel Header error: ")
}
SignatureHeader

该结构包含创建者详细信息,该详细信息包含Mspid(成员服务提供者的身份证书)。

type SignatureHeader struct {
   Creator []byte
   Nonce   []byte
}

其中Creator可通过msp.SerializedIdentity解析。

从Payload中获取SignatureHeader
signatureHeader := &common.SignatureHeader{}
err := proto.Unmarshal(payload.Header.SignatureHeader, signatureHeader)
if err != nil {
   return SignatureHeader{}, errors.WithMessage(err,"unmarshaling Signature Header error: ")
}
从SignatureHeader中获取Creator
type SerializedIdentity struct {
	 Mspid   string
	 IdBytes []byte 
}

creator := &msp.SerializedIdentity{}
err = proto.Unmarshal(signatureHeader.Creator, creator)
if err != nil {
	 return SignatureHeader{}, errors.WithMessage(err,"unmarshaling Creator error: ")
}
从Creator中解析IdBytes(MSP)
uEnc := base64.URLEncoding.EncodeToString([]byte(creator.IdBytes))

	certText, err := base64.URLEncoding.DecodeString(uEnc)
	if err != nil {
		return SignatureHeader{}, errors.WithMessage(err,"Error decoding string: ")
	}
			
	end, _ := pem.Decode([]byte(string(certText)))
	if end == nil {
		return SignatureHeader{}, errors.New("Error Pem decoding: ")
	}
	cert, err := x509.ParseCertificate(end.Bytes)
	if err != nil {
		return SignatureHeader{}, errors.New("failed to parse certificate:: ")
	}		

	certificateJson :=	Certificate{
		Country:		cert.Issuer.Country,
		Organization:		cert.Issuer.Organization,
		OrganizationalUnit:	cert.Issuer.OrganizationalUnit,
		Locality:		cert.Issuer.Locality,
		Province:		cert.Issuer.Province,
		SerialNumber:		cert.Issuer.SerialNumber,
		NotBefore:		cert.NotBefore,
		NotAfter:		cert.NotAfter,								
	}

Payload Data

包含了区块中的所有交易数据及链码调用及响应数据

TransactionAction
type TransactionAction struct {
    Header  []byte 
    Payload []byte 
}

Header: 和SignatureHeader差不多,包含了用于提交交易的身份详细信息

Payload: 可以通过ChainCodeActionPayload解析

ChainCodeActionPayload
type ChaincodeActionPayload struct {
     ChaincodeProposalPayload []byte 
     Action *ChaincodeEndorsedAction 
}
ChaincodeProposalPayload

包含了调用chaincode时的输入参数等

type ChaincodeProposalPayload struct {
   Input  	[]byte
   TransientMap map[string][]byte
}

Input: 可以通过ChaincodeInvocationSpec解析

ChaincodeInvocationSpec

包含链码信息和调用期间使用的参数。

type ChaincodeInvocationSpec struct {
     ChaincodeSpec  *ChaincodeSpec
}
type ChaincodeSpec struct {
     Type 	  ChaincodeSpec_Type 
     ChaincodeId *ChaincodeID
     Input       *ChaincodeInput
     Timeout     int32
}
type ChaincodeInput struct {
     Args        [][]byte
     Decorations map[string][]byte
}
Action

可通过ChaincodeEndorsedAction解析,包含Proposal Hash及调用链码时的Read/Write的交易信息

type ChaincodeEndorsedAction struct {
     ProposalResponsePayload []byte
     Endorsements  []*Endorsement
}

type ProposalResponsePayload struct {
     ProposalHash []byte
     Extension    []byte   
}

Extension可通过ChaincodeAction来解析,包含了Read/Write操作的交易

Read/Write Set
type ChaincodeAction struct {
     Results  []byte 
     Events   []byte 
     Response *Response 
}
Results

可通过TxReadWriteSet解析

type KVRWSet struct {
	Reads            []*KVRead         
	RangeQueriesInfo []*RangeQueryInfo 
	Writes           []*KVWrite  
	MetadataWrites   []*KVMetadataWrite      
}

type KVRead struct {
	Key     string   
	Version *Version 
}

type Version struct {
	BlockNum uint64 
	TxNum    uint64 
}

type KVWrite struct {
	Key      string 
	IsDelete bool   
	Value    []byte 
}

type RangeQueryInfo struct {
	StartKey     string 
	EndKey       string 
	ItrExhausted bool   
	ReadsInfo isRangeQueryInfo_ReadsInfo 
}

type KVMetadataWrite struct {
	Key      string
	Entries  []*KVMetadataEntry
}

type KVMetadataEntry struct {
	Name     string
	Value    []byte
}

结语

如果是做区块链浏览器,上述解析已经足够了,可根据具体情况做适应调整。

  • 9
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值