fabric如何解析一个common.block的内容

CodingCode · · 1711 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

fabric如何解析一个common.block的内容

在前面的文章 “fabric如何从ledger里面读取block的内容” 中我们介绍了如何从ledger文件里面读取一个block,然后把block的内容写到一个文件中,再使用工具configtxlator把block内容翻译成json,这样用户就可以读取block的内容了。

这篇文章中我们直接用golang借助于fabric本身的代码,利用代码来解析和读取block的内容;也就是说当我们得到一个common.block对象时,我们直接利用fabric的数据结构和函数访问block的内容,而不需要借助configtxlator。

这部分代码是一个框架,不能单独编译,必须借助于前面提到的文章"fabric如何从ledger里面读取block的内容”的部分代码。

主函数

接受一个common.block对象,然后根据是Config block还是Endorser Transaction block分别解析。

包含:

  • block number
  • block hash value
  • channel
  • txid
  • creator
package main

import (
    "fmt"
    "encoding/base64"

    "github.com/golang/protobuf/proto"

    "github.com/hyperledger/fabric/protos/common"
    "github.com/hyperledger/fabric/protos/utils"
    "github.com/hyperledger/fabric/protos/peer"
    "github.com/hyperledger/fabric/common/configtx"
    "github.com/hyperledger/fabric/core/ledger/util"
    "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
)

func parseBlock(block *common.Block) error {
    var err error

    // Handle header
    fmt.Printf("Block: Number=[%d], CurrentBlockHash=[%s], PreviousBlockHash=[%s]\n",
                        block.GetHeader().Number,
                        base64.StdEncoding.EncodeToString(block.GetHeader().DataHash),
                        base64.StdEncoding.EncodeToString(block.GetHeader().PreviousHash))

    // Handle transaction
    var tranNo int64 = -1
    txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
    if len(txsFilter) == 0 {
        txsFilter = util.NewTxValidationFlags(len(block.Data.Data))
        block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
    }

    for _, envBytes := range block.Data.Data {
        tranNo++
        if txsFilter.IsInvalid(int(tranNo)) {
            fmt.Printf("    Transaction: No=[%d], Status=[INVALID]\n", tranNo)
            continue
        } else {
            fmt.Printf("    Transaction: No=[%d], Status=[VALID]\n",   tranNo)
        }

        var env *common.Envelope
        if env, err = utils.GetEnvelopeFromBlock(envBytes); err != nil {
            return err
        }

        var payload *common.Payload
        if payload, err = utils.GetPayload(env); err != nil {
            return err
        }

        var chdr *common.ChannelHeader
        if chdr, err = utils.UnmarshalChannelHeader(payload.Header.ChannelHeader); err != nil {
            return err
        }
        fmt.Printf("        txid=[%s], channel=[%s]\n", chdr.TxId, chdr.ChannelId)

        var shdr *common.SignatureHeader
        if shdr, err = utils.GetSignatureHeader(payload.Header.SignatureHeader); err != nil {
            return err
        }

        var mspid, subject string
        if mspid, subject, err = decodeSerializedIdentity(shdr.Creator); err != nil {
            return err
        }
        fmt.Printf("        creator=[%s:%s]\n", mspid, subject)

        if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG {
            fmt.Printf("        type=[CONFIG]\n")
            if err = parseConfig(payload); err != nil {
                return err
            }
        } else if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
            fmt.Printf("        type=[ENDORSER_TRANSACTION]\n")
            if err = parseEndorserTransaction(payload); err != nil {
                return err
            }
        } else {
            fmt.Printf("        txid=[%s], channel=[%s], type=[UNKNOWN]\n", chdr.TxId, chdr.ChannelId)
        }
    }

    return nil
}

解析endorser transaction block

这个解析并不完整,只是我们项目中需要的字段进行了解析,其他的丢弃了。
主要包括:

  • endorsers
  • RWSet (chaincode, key)
func parseEndorserTransaction(payload *common.Payload) error {
    var err error
    var tx *peer.Transaction
    if tx, err = utils.GetTransaction(payload.Data); err != nil {
        return err
    }

    fmt.Printf("        actions\n")
    for _, action := range tx.Actions {
        var capayload *peer.ChaincodeActionPayload
        var ca        *peer.ChaincodeAction
        if capayload, ca, err = utils.GetPayloads(action); err != nil {
            return err
        }

        fmt.Printf("            endorsers\n")
        for _, endorser := range capayload.Action.Endorsements {
            var mspid, subject string
            if mspid, subject, err = decodeSerializedIdentity(endorser.Endorser); err != nil {
                return err
            }
            fmt.Printf("                endorser[%s:%s]\n", mspid, subject)
        }

        fmt.Printf("            RWSet\n")
        txRWSet := &rwsetutil.TxRwSet{}
        if err = txRWSet.FromProtoBytes(ca.Results); err != nil {
            return err
        }
        for _, nsRWSet := range txRWSet.NsRwSets {
            ns := nsRWSet.NameSpace
            if ns != "lscc" {   // skip system chaincode
                fmt.Printf("                ns=[%v]\n", ns)
                fmt.Printf("                RDSet\n")
                for _, kvRead := range nsRWSet.KvRwSet.Reads {
                            fmt.Printf("                     key=[%v]\n", kvRead.Key)
                }
                fmt.Printf("                WRSet\n")
                for _, kvWrite := range nsRWSet.KvRwSet.Writes {
                    if kvWrite.IsDelete {
                        fmt.Printf("                     key=[%v] op=[delete]\n", kvWrite.Key)
                    } else {
                        fmt.Printf("                     key=[%v] op=[write]\n",  kvWrite.Key)
                    }
                }
            }
        }
    }
    return nil
}

解析 config block

和前面一样,也没有解析整个config block,只解析了我们项目中需要的字段,其实只有一个orderer address,当然其他的也很容易处理了。

func parseConfig(payload *common.Payload) error {
    var err error

    var configEnvelope *common.ConfigEnvelope
    if configEnvelope, err = configtx.UnmarshalConfigEnvelope(payload.Data); err != nil {
        return err
    }

    var configGroup * common.ConfigGroup = configEnvelope.Config.ChannelGroup
    fmt.Printf("        Groups\n")
    for k, _ := range configGroup.Groups {
        fmt.Printf("            %s\n", k)
    }

    fmt.Printf("        Values\n")
    for k, v := range configGroup.Values {
        fmt.Printf("            %s\n", k)
        if k == "OrdererAddresses" {
            addresses := &common.OrdererAddresses{}
            if err = proto.Unmarshal(v.Value, addresses); err != nil {
                return err
            }
            for _, address := range addresses.Addresses {
                fmt.Printf("                [%s]\n",  address)
            }
        }
    }
    return nil
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:CodingCode

查看原文:fabric如何解析一个common.block的内容

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1711 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传