前言
本文来自`fabric-contract-api-go`api手册,基于Hyperledger Fabric2.2.2开发提示:以下是本篇文章正文内容,下面案例可供参考
声明合约
The first thing we will do here is declare a contract for use in our chaincode.
所有合约第一件事就是继承或者实现接口
implement the contractapi.ContractInterface
embed the contractapi.Contract
struct within your own contract
package main
import (
"errors"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SimpleContract contract for handling writing and reading from the world state
type SimpleContract struct {
contractapi.Contract
}
编写合约
规则
参数类型说明
交易合约的第一个参数必须type *contractapi.TransactionContext
or contractapi.TransactionContextInterface
返回值个数与说明
编写
Create
当交易时需要提供交易上下文,但是我们采用contractapi.TransactionContext
提供的默认事务上下文,因为它提供了与世界状态进行交互的所有必要功能。也可以使用contractapi.TransactionContextInterface
// 写入数据样例函数,其中ctx.GetStub().就相当于stub.更进一层的封装
// Create adds a new key with value to the world state
func (sc *SimpleContract) Create(ctx contractapi.TransactionContextInterface,
key string, value string) error {
existing, err := ctx.GetStub().GetState(key)
if err != nil {
return errors.New("Unable to interact with world state")
}
if existing != nil {
return fmt.Errorf("Cannot create world state pair with key %s. Already
exists", key)
}
err = ctx.GetStub().PutState(key, []byte(value))
if err != nil {
return errors.New("Unable to interact with world state")
}
return nil
}
update
// 与create区别在于existng == nil
// Update changes the value with key in the world state
func (sc *SimpleContract) Update(ctx contractapi.TransactionContextInterface,
key string, value string) error {
existing, err := ctx.GetStub().GetState(key)
if err != nil {
return errors.New("Unable to interact with world state")
}
if existing == nil {
return fmt.Errorf("Cannot update world state pair with key %s. Does not
exist", key)
}
err = ctx.GetStub().PutState(key, []byte(value))
if err != nil {
return errors.New("Unable to interact with world state")
}
return nil
}
read
// Read returns the value at key in the world state
func (sc *SimpleContract) Read(ctx contractapi.TransactionContextInterface, key
string) (string, error) {
existing, err := ctx.GetStub().GetState(key)
if err != nil {
return "", errors.New("Unable to interact with world state")
}
if existing == nil {
return "", fmt.Errorf("Cannot read world state pair with key %s. Does
not exist", key)
}
return string(existing), nil
}
在链码中使用合约
package main
import (
"errors"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SimpleContract contract for handling writing and reading from the world state
type SimpleContract struct {
contractapi.Contract
}
// Create adds a new key with value to the world state
func (sc *SimpleContract) Create(ctx contractapi.TransactionContextInterface, key string, value string) error {
existing, err := ctx.GetStub().GetState(key)
if err != nil {
return errors.New("Unable to interact with world state")
}
if existing != nil {
return fmt.Errorf("Cannot create world state pair with key %s. Already exists", key)
}
err = ctx.GetStub().PutState(key, []byte(value))
if err != nil {
return errors.New("Unable to interact with world state")
}
return nil
}
// Update changes the value with key in the world state
func (sc *SimpleContract) Update(ctx contractapi.TransactionContextInterface, key string, value string) error {
existing, err := ctx.GetStub().GetState(key)
if err != nil {
return errors.New("Unable to interact with world state")
}
if existing == nil {
return fmt.Errorf("Cannot update world state pair with key %s. Does not exist", key)
}
err = ctx.GetStub().PutState(key, []byte(value))
if err != nil {
return errors.New("Unable to interact with world state")
}
return nil
}
// Read returns the value at key in the world state
func (sc *SimpleContract) Read(ctx contractapi.TransactionContextInterface, key string) (string, error) {
existing, err := ctx.GetStub().GetState(key)
if err != nil {
return "", errors.New("Unable to interact with world state")
}
if existing == nil {
return "", fmt.Errorf("Cannot read world state pair with key %s. Does not exist", key)
}
return string(existing), nil
}
package main
import (
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
func main() {
}
链码必须满足shim.Chaincode
接口, 要有两个函数 Init
和Invoke
。但幸运的是,您不需要编写这些代码,因为contractapi
提供了一种根据一个或多个合同生成链码的方法。要创建一个链码,请在main
函数中添加以下内容:
simpleContract := new(SimpleContract)
cc, err := contractapi.NewChaincode(simpleContract)
if err != nil {
panic(err.Error())
}
//start以方便合约能够调用
if err := cc.Start(); err != nil {
panic(err.Error())
}
package main
import (
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
func main() {
simpleContract := new(SimpleContract)
cc, err := contractapi.NewChaincode(simpleContract)
if err != nil {
panic(err.Error())
}
if err := cc.Start(); err != nil {
panic(err.Error())
}
}
调用合约
peer chaincode instantiate -n mycc -v 0 -c '{"Args":[]}' -C myc
peer chaincode invoke -n mycc -c '{"Args":["Create", "KEY_1", "VALUE_1"]}' -C myc
peer chaincode invoke -n mycc -c '{"Args":["Update", "KEY_1", "VALUE_2"]}' -C myc
peer chaincode query -n mycc -c '{"Args":["Read", "KEY_1"]}' -C myc
参考文献:官方api教程