基于fabric 0.6定制智能合约

来源:互联网 发布:中美进出口数据 编辑:程序博客网 时间:2024/05/29 19:27

  • fabric部署与管理
    • 1 git地址
    • 2 部署
    • 3 使用chaincode
  • fabric源码智能合约源码解析
    • 1 go语言又称golang
    • 2 智能合约例子
    • 3 核心接口
  • 定制智能合约
    • 1 智能合约
    • 2 编译调试

目前fabric 0.6为稳定版本,fabric 1.0为最新版,并持续更新中

IBM中国研究院开发的超能云(SuperVessel)平台提供了给区块链爱好者、开发者的区块链开发测试环境。通过该平台,用户能够免费、超快速创建基于Hyperledger Fabric的多节点区块链、并在自己的链上花式玩转智能合约。
https://my.oschina.net/u/1431433/blog/712869

1 fabric部署与管理

1.1 git地址

https://github.com/hyperledger/fabric
默认是最新版1.0,可以自己切换到v0.6分支

1.2 部署

环境:Ubuntu 16.04 64位
安装Docker,Docker-compose,fabric部署,以pbft模式启动fabric
参考文档:http://www.cnblogs.com/sclczk/p/6552845.html

重启服务

systemctl restart docker.service

启动 4 个 PBFT peer 节点 + 1 个 CA 节点 + 1 个 Blockchain-explorer,并启用 CA 功能。

docker-compose -f 4-peers-with-membersrvc-explorer.yml up

1.3 使用chaincode

https://yeasy.gitbooks.io/blockchain_guide/content/fabric/v0.6/usage.html
或参考https://bitshuo.com/topic/58870c418d8be16a4ff73081

进入一个节点

docker exec -it pbft_vp0_1 bash

2 fabric源码智能合约源码解析

2.1 go语言(又称golang)

go IDE:Gogland
http://www.mamicode.com/info-detail-1701831.html

2.2 智能合约例子

相关例子在如下文件夹中
这里写图片描述
这里列举了如何做一个map和table

2.3 核心接口

在fabric/core/chaincode/shim中的interfaces.go

type ChaincodeStubInterface interface {    // Get the arguments to the stub call as a 2D byte array    GetArgs() [][]byte    // Get the arguments to the stub call as a string array    GetStringArgs() []string    // Get the transaction ID    GetTxID() string    // InvokeChaincode locally calls the specified chaincode `Invoke` using the    // same transaction context; that is, chaincode calling chaincode doesn't    // create a new transaction message.    InvokeChaincode(chaincodeName string, args [][]byte) ([]byte, error)    // QueryChaincode locally calls the specified chaincode `Query` using the    // same transaction context; that is, chaincode calling chaincode doesn't    // create a new transaction message.    QueryChaincode(chaincodeName string, args [][]byte) ([]byte, error)    // GetState returns the byte array value specified by the `key`.    GetState(key string) ([]byte, error)    // PutState writes the specified `value` and `key` into the ledger.    PutState(key string, value []byte) error    // DelState removes the specified `key` and its value from the ledger.    DelState(key string) error    // RangeQueryState function can be invoked by a chaincode to query of a range    // of keys in the state. Assuming the startKey and endKey are in lexical    // an iterator will be returned that can be used to iterate over all keys    // between the startKey and endKey, inclusive. The order in which keys are    // returned by the iterator is random.    RangeQueryState(startKey, endKey string) (StateRangeQueryIteratorInterface, error)    // CreateTable creates a new table given the table name and column definitions    CreateTable(name string, columnDefinitions []*ColumnDefinition) error    // GetTable returns the table for the specified table name or ErrTableNotFound    // if the table does not exist.    GetTable(tableName string) (*Table, error)    // DeleteTable deletes an entire table and all associated rows.    DeleteTable(tableName string) error    // InsertRow inserts a new row into the specified table.    // Returns -    // true and no error if the row is successfully inserted.    // false and no error if a row already exists for the given key.    // false and a TableNotFoundError if the specified table name does not exist.    // false and an error if there is an unexpected error condition.    InsertRow(tableName string, row Row) (bool, error)    // ReplaceRow updates the row in the specified table.    // Returns -    // true and no error if the row is successfully updated.    // false and no error if a row does not exist the given key.    // flase and a TableNotFoundError if the specified table name does not exist.    // false and an error if there is an unexpected error condition.    ReplaceRow(tableName string, row Row) (bool, error)    // GetRow fetches a row from the specified table for the given key.    GetRow(tableName string, key []Column) (Row, error)    // GetRows returns multiple rows based on a partial key. For example, given table    // | A | B | C | D |    // where A, C and D are keys, GetRows can be called with [A, C] to return    // all rows that have A, C and any value for D as their key. GetRows could    // also be called with A only to return all rows that have A and any value    // for C and D as their key.    GetRows(tableName string, key []Column) (<-chan Row, error)    // DeleteRow deletes the row for the given key from the specified table.    DeleteRow(tableName string, key []Column) error    // ReadCertAttribute is used to read an specific attribute from the transaction certificate,    // *attributeName* is passed as input parameter to this function.    // Example:    //  attrValue,error:=stub.ReadCertAttribute("position")    ReadCertAttribute(attributeName string) ([]byte, error)    // VerifyAttribute is used to verify if the transaction certificate has an attribute    // with name *attributeName* and value *attributeValue* which are the input parameters    // received by this function.    // Example:    //    containsAttr, error := stub.VerifyAttribute("position", "Software Engineer")    VerifyAttribute(attributeName string, attributeValue []byte) (bool, error)    // VerifyAttributes does the same as VerifyAttribute but it checks for a list of    // attributes and their respective values instead of a single attribute/value pair    // Example:    //    containsAttrs, error:= stub.VerifyAttributes(&attr.Attribute{"position",  "Software Engineer"}, &attr.Attribute{"company", "ACompany"})    VerifyAttributes(attrs ...*attr.Attribute) (bool, error)    // VerifySignature verifies the transaction signature and returns `true` if    // correct and `false` otherwise    VerifySignature(certificate, signature, message []byte) (bool, error)    // GetCallerCertificate returns caller certificate    GetCallerCertificate() ([]byte, error)    // GetCallerMetadata returns caller metadata    GetCallerMetadata() ([]byte, error)    // GetBinding returns the transaction binding    GetBinding() ([]byte, error)    // GetPayload returns transaction payload, which is a `ChaincodeSpec` defined    // in fabric/protos/chaincode.proto    GetPayload() ([]byte, error)    // GetTxTimestamp returns transaction created timestamp, which is currently    // taken from the peer receiving the transaction. Note that this timestamp    // may not be the same with the other peers' time.    GetTxTimestamp() (*timestamp.Timestamp, error)    // SetEvent saves the event to be sent when a transaction is made part of a block    SetEvent(name string, payload []byte) error}

3 定制智能合约

3.1 智能合约

写的一个例子:

package mainimport (    "errors"    "fmt"    "encoding/json"    "github.com/hyperledger/fabric/core/chaincode/shim")// SimpleChaincode example simple Chaincode implementationtype SimpleChaincode struct {}func main() {    err := shim.Start(new(SimpleChaincode))    if err != nil {        fmt.Printf("Error starting Simple chaincode: %s", err)    }}type Location struct {    Id string    Status string    locx string    locy string}// Init resets all the thingsfunc (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {    if len(args) != 1 {        return nil, errors.New("Incorrect number of arguments. Expecting 1")    }    return nil, nil}// Invoke isur entry point to invoke a chaincode functionfunc (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {    fmt.Println("invoke is running " + function)    // Handle different functions    if function == "init" {        return t.Init(stub, "init", args)    } else if function == "write" {        return t.write(stub, args)    }    fmt.Println("invoke did not find func: " + function)    return nil, errors.New("Received unknown function invocation")}// Query is our entry point for queriesfunc (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {    fmt.Println("query is running " + function)    // Handle different functions    if function == "read" { //read a variable        return t.read(stub, args)    }    fmt.Println("query did not find func: " + function)    return nil, errors.New("Received unknown function query")}// write - invoke function to write key/value pairfunc (t *SimpleChaincode) write(stub shim.ChaincodeStubInterface, args []string) ([]byte,error) {    if len(args) != 4{        return nil, errors.New("Incorrect number of arguments. Expecting 4")    }    var err error    location := Location {Id:args[0],Status:args[1]+","+args[2]+","+args[3],locx:args[2],locy:args[3]}    locationlBytes,err:= json.Marshal(&location)    str := string(locationlBytes[:])    fmt.Println(str)    if err != nil{        fmt.Print(err)    }    err = stub.PutState(location.Id,locationlBytes)    if err !=nil{        return nil,errors.New("PutState Error" + err.Error())    }    return nil,nil}// read - query function to read key/value pairfunc (t *SimpleChaincode) read(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {    var key, jsonResp string    var err error    if len(args) != 1 {        return nil, errors.New("Incorrect number of arguments. Expecting name of the key to query")    }    key = args[0]    valAsbytes, err := stub.GetState(key)    if err != nil {        jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}"        return nil, errors.New(jsonResp)    }    return valAsbytes, nil}

3.2 编译调试

go build
http://blog.csdn.net/h363659487/article/details/72768211

部署自己写的智能合约时,先上传到github,然后进入一个vp节点:
docker exec -it pbft_vp0_1 bash
通过github下载到节点里面。
这里写图片描述
注意路径中的github.com其实就是一个文件名

原创粉丝点击