目前fabric 0.6为稳定版本,fabric 1.0为最新版,并持续更新中
IBM中国研究院开发的超能云(SuperVessel)平台提供了给区块链爱好者、开发者的区块链开发测试环境。通过该平台,用户能够免费、超快速创建基于Hyperledger Fabric的多节点区块链、并在自己的链上花式玩转智能合约。
https://my.oschina.net/u/1431433/blog/712869
https://github.com/hyperledger/fabric
默认是最新版1.0,可以自己切换到v0.6分支
环境: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
https://yeasy.gitbooks.io/blockchain_guide/content/fabric/v0.6/usage.html
或参考https://bitshuo.com/topic/58870c418d8be16a4ff73081
进入一个节点
docker exec -it pbft_vp0_1 bash
go IDE:Gogland
http://www.mamicode.com/info-detail-1701831.html
相关例子在如下文件夹中
这里列举了如何做一个map和table
在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
}
写的一个例子:
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
}
go build
http://blog.csdn.net/h363659487/article/details/72768211
部署自己写的智能合约时,先上传到github,然后进入一个vp节点:
docker exec -it pbft_vp0_1 bash
,
通过github下载到节点里面。
注意路径中的github.com其实就是一个文件名