Go 从价值看世界状态

Go 从价值看世界状态,go,blockchain,hyperledger,hyperledger-fabric,Go,Blockchain,Hyperledger,Hyperledger Fabric,我是区块链新手,正在使用hyperledger fabric(目前为v:0.6)创建学习视角应用程序 我在区块链上保留金融交易的分类账,只要交易发生(基于web的组件在交易发生时通知并调用链码) 事务的结构如下所示: type Transactions struct { ReferenceNumber string `json:"ReferenceNumber"` BillNumber string `json:"BillNumber"` BillingCompany

我是区块链新手,正在使用hyperledger fabric(目前为v:0.6)创建学习视角应用程序

我在区块链上保留金融交易的分类账,只要交易发生(基于web的组件在交易发生时通知并调用链码)

事务的结构如下所示:

type Transactions struct { 
    ReferenceNumber string `json:"ReferenceNumber"`
    BillNumber string `json:"BillNumber"`
    BillingCompany string `json:"BillingCompany"`
    Amount string `json:"Amount"`
    Status string `json:"Status"`
}
我对其进行json封送,并将其保存为以ReferenceNumber作为键的状态

现在我可以根据ReferenceNumber从state获取事务。但是,如果我想根据“状态”从state获取交易,比如分类账上有多少交易的状态为“已对账”,该怎么办


有没有办法不根据键而是根据值来查询状态?

Worldstate级别的存储工作在{key,value}级别。很明显,它只用于指定键的单值查找。我认为,您正在寻找的是对WorldState的下一个更高层次的抽象,即所谓的表构造。 fabric/examples/chaincode/go/asset\u management\u interactive/asset\u management.go有一个关于如何创建包含所需列的表的示例。在定义数据结构的主键以保存事务时,可以将状态作为键之一,并且还可以根据状态检索数据

创建该表的一些示例代码如下所示

func createTableTwo(stub shim.ChaincodeStubInterface) error {
    var columnDefsTableTwo []*shim.ColumnDefinition
    columnOneTableTwoDef := shim.ColumnDefinition{Name: "colOneTableTwo",
        Type: shim.ColumnDefinition_STRING, Key: true}
    columnTwoTableTwoDef := shim.ColumnDefinition{Name: "colTwoTableTwo",
        Type: shim.ColumnDefinition_INT32, Key: false}
    columnThreeTableTwoDef := shim.ColumnDefinition{Name: "colThreeTableThree",
        Type: shim.ColumnDefinition_INT32, Key: true}
    columnFourTableTwoDef := shim.ColumnDefinition{Name: "colFourTableFour",
        Type: shim.ColumnDefinition_STRING, Key: true}
    columnDefsTableTwo = append(columnDefsTableTwo, &columnOneTableTwoDef)
    columnDefsTableTwo = append(columnDefsTableTwo, &columnTwoTableTwoDef)
    columnDefsTableTwo = append(columnDefsTableTwo, &columnThreeTableTwoDef)
    columnDefsTableTwo = append(columnDefsTableTwo, &columnFourTableTwoDef)
    return stub.CreateTable("tableTwo", columnDefsTableTwo)
}
if len(args) < 1 {
            return nil, errors.New("getRowsTableTwo failed. Must include at least key values")
        }

        var columns []shim.Column

        col1Val := args[0]
        col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}}
        columns = append(columns, col1)

        if len(args) > 1 {
            col2Int, err := strconv.ParseInt(args[1], 10, 32)
            if err != nil {
                return nil, errors.New("getRowsTableTwo failed. arg[1] must be convertable to int32")
            }
            col2Val := int32(col2Int)
            col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}}
            columns = append(columns, col2)
        }

        rowChannel, err := stub.GetRows("tableTwo", columns)
        if err != nil {
            return nil, fmt.Errorf("getRowsTableTwo operation failed. %s", err)
        }

        var rows []shim.Row
        for {
            select {
            case row, ok := <-rowChannel:
                if !ok {
                    rowChannel = nil
                } else {
                    rows = append(rows, row)
                }
            }
            if rowChannel == nil {
                break
            }
        }

        jsonRows, err := json.Marshal(rows)
        if err != nil {
            return nil, fmt.Errorf("getRowsTableTwo operation failed. Error marshaling JSON: %s", err)
        }

        return jsonRows, nil
现在将数据插入此表,如图所示

if len(args) < 4 {
            return nil, errors.New("insertRowTableTwo failed. Must include 4 column values")
        }

        col1Val := args[0]
        col2Int, err := strconv.ParseInt(args[1], 10, 32)
        if err != nil {
            return nil, errors.New("insertRowTableTwo failed. arg[1] must be convertable to int32")
        }
        col2Val := int32(col2Int)
        col3Int, err := strconv.ParseInt(args[2], 10, 32)
        if err != nil {
            return nil, errors.New("insertRowTableTwo failed. arg[2] must be convertable to int32")
        }
        col3Val := int32(col3Int)
        col4Val := args[3]

        var columns []*shim.Column
        col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}}
        col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}}
        col3 := shim.Column{Value: &shim.Column_Int32{Int32: col3Val}}
        col4 := shim.Column{Value: &shim.Column_String_{String_: col4Val}}
        columns = append(columns, &col1)
        columns = append(columns, &col2)
        columns = append(columns, &col3)
        columns = append(columns, &col4)

        row := shim.Row{Columns: columns}
        ok, err := stub.InsertRow("tableTwo", row)
        if err != nil {
            return nil, fmt.Errorf("insertRowTableTwo operation failed. %s", err)
        }
        if !ok {
            return nil, errors.New("insertRowTableTwo operation failed. Row with given key already exists")
        }
如果len(args)<4{
返回nil,errors.New(“insertRowTableTwo失败。必须包含4列值”)
}
col1Val:=args[0]
col2Int,err:=strconv.ParseInt(args[1],10,32)
如果出错!=零{
返回nil,errors.New(“insertRowTableTwo失败。arg[1]必须可转换为int32”)
}
col2Val:=int32(col2Int)
col3Int,err:=strconv.ParseInt(args[2],10,32)
如果出错!=零{
返回nil,errors.New(“insertRowTableTwo失败。arg[2]必须可转换为int32”)
}
col3Val:=int32(col3Int)
col4Val:=args[3]
变量列[]*shim.Column
col1:=shim.Column{Value:&shim.Column_ustring{String_uu:col1Val}
col2:=shim.Column{Value:&shim.Column_Int32{Int32:col2Val}
col3:=shim.Column{Value:&shim.Column_Int32{Int32:col3Val}
col4:=shim.Column{Value:&shim.Column_ustring{String_uu:col4Val}
columns=append(列和列1)
columns=append(列和列2)
columns=append(列和列3)
columns=append(列和列4)
行:=垫片。行{列:列}
好的,错误:=stub.InsertRow(“tableTwo”,row)
如果出错!=零{
返回nil,fmt.Errorf(“insertRowTableTwo操作失败。%s”,错误)
}
如果!嗯{
返回nil,errors.New(“insertRowTableTwo操作失败。具有给定键的行已存在”)
}
现在,要通过不指定所有键来查询此数据,请执行以下操作

func createTableTwo(stub shim.ChaincodeStubInterface) error {
    var columnDefsTableTwo []*shim.ColumnDefinition
    columnOneTableTwoDef := shim.ColumnDefinition{Name: "colOneTableTwo",
        Type: shim.ColumnDefinition_STRING, Key: true}
    columnTwoTableTwoDef := shim.ColumnDefinition{Name: "colTwoTableTwo",
        Type: shim.ColumnDefinition_INT32, Key: false}
    columnThreeTableTwoDef := shim.ColumnDefinition{Name: "colThreeTableThree",
        Type: shim.ColumnDefinition_INT32, Key: true}
    columnFourTableTwoDef := shim.ColumnDefinition{Name: "colFourTableFour",
        Type: shim.ColumnDefinition_STRING, Key: true}
    columnDefsTableTwo = append(columnDefsTableTwo, &columnOneTableTwoDef)
    columnDefsTableTwo = append(columnDefsTableTwo, &columnTwoTableTwoDef)
    columnDefsTableTwo = append(columnDefsTableTwo, &columnThreeTableTwoDef)
    columnDefsTableTwo = append(columnDefsTableTwo, &columnFourTableTwoDef)
    return stub.CreateTable("tableTwo", columnDefsTableTwo)
}
if len(args) < 1 {
            return nil, errors.New("getRowsTableTwo failed. Must include at least key values")
        }

        var columns []shim.Column

        col1Val := args[0]
        col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}}
        columns = append(columns, col1)

        if len(args) > 1 {
            col2Int, err := strconv.ParseInt(args[1], 10, 32)
            if err != nil {
                return nil, errors.New("getRowsTableTwo failed. arg[1] must be convertable to int32")
            }
            col2Val := int32(col2Int)
            col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}}
            columns = append(columns, col2)
        }

        rowChannel, err := stub.GetRows("tableTwo", columns)
        if err != nil {
            return nil, fmt.Errorf("getRowsTableTwo operation failed. %s", err)
        }

        var rows []shim.Row
        for {
            select {
            case row, ok := <-rowChannel:
                if !ok {
                    rowChannel = nil
                } else {
                    rows = append(rows, row)
                }
            }
            if rowChannel == nil {
                break
            }
        }

        jsonRows, err := json.Marshal(rows)
        if err != nil {
            return nil, fmt.Errorf("getRowsTableTwo operation failed. Error marshaling JSON: %s", err)
        }

        return jsonRows, nil
如果len(args)<1{
返回nil,errors.New(“getRowsTableTwo失败。必须至少包含键值”)
}
var columns[]shim.Column
col1Val:=args[0]
col1:=shim.Column{Value:&shim.Column_ustring{String_uu:col1Val}
columns=append(列,col1)
如果len(args)>1{
col2Int,err:=strconv.ParseInt(args[1],10,32)
如果错误!=零{
返回nil,errors.New(“getRowsTableTwo失败。arg[1]必须可转换为int32”)
}
col2Val:=int32(col2Int)
col2:=shim.Column{Value:&shim.Column_Int32{Int32:col2Val}
columns=append(columns,col2)
}
rowChannel,err:=stub.GetRows(“tableTwo”,columns)
如果出错!=零{
返回nil,fmt.Errorf(“getRowsTableTwo操作失败。%s”,错误)
}
变量行[]shim.Row
为了{
挑选{

案例行,确定:=在Hyperledger Fabric v1.0中,您可以将数据建模为JSON,并使用CouchDB作为状态数据库。在这种情况下,您可以直接查询JSON的任何字段

中有这样一个数据模式的示例


.

谢谢@Ashishkel的详细解释。我现在正在使用表来解决这个问题。我设置了两列(ReferenceNumber和Status)作为键列,现在当我使用2个参数进行查询时,返回表中的结果,但当我使用2个参数中的任何一个进行查询时,查询都无法返回任何行。我使用的代码与gerrit/src/github.com/hyperledger/fabric/bddtests/chaincode/go/table/table.g中描述的代码相同。我注意到,当前版本可能存在这样的问题ed是,假设您有A、B键(按相同顺序指定)然后,当我既不指定任何一个键,也不指定A时,GetRows起作用。当我单独指定B时,GetRows不起作用。试试看。如果你遇到的是相同的问题,那么这是一种前进的方法。确切地说,它在没有任何参数、所有键或第一个键的情况下都起作用。我必须颠倒键的顺序来创建工作-A谢谢你的帮助,干杯。