基于fabric 0.6定制智能合约

  • 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 智能合约例子

相关例子在如下文件夹中
基于fabric 0.6定制智能合约_第1张图片
这里列举了如何做一个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 main

import (
    "errors"
    "fmt"
    "encoding/json"
    "github.com/hyperledger/fabric/core/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type 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 things
func (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 function
func (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 queries
func (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 pair
func (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 pair
func (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其实就是一个文件名

你可能感兴趣的:(区块链,智能合约,fabric0-6,go语言)