我正在使用fabric-sdk-go来安装,实例化,调用和查询链码。
链码安装成功。
root@991bc7577959:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode list --installed
Get installed chaincodes on peer:
Name: myproject, Version: 1.0, Path: github.com/hyperledger/myproject/chaincode/, Id: 130607a18ab3fe332854d7c2048f04b89e3c740e1ffa97c76c9ced266e6714ca
链码实例化。
ccPolicy := cauthdsl.SignedByAnyMember([]string{"Seller", "Buyer"})
fmt.Println("Value of ccPolicy is: ", ccPolicy)
resp, err := setup.admin.InstantiateCC(setup.ChannelID,
resmgmt.InstantiateCCRequest{
Name: setup.ChainCodeID,
Path: setup.ChaincodeGoPath,
Version: "1.0",
Args: [][]byte{[]byte("init"), []byte("Seller"), []byte("100"), []byte("Buyer"), []byte("200")},
Policy: ccPolicy,
})
root@991bc7577959:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode list --instantiated -C mychannel
Get instantiated chaincodes on channel mychannel:
Name: myproject, Version: 1.0, Path: github.com/hyperledger/myproject/chaincode/, Input: <nil>, Escc: escc, Vscc: vscc
查询链码
func (setup *FabricSetup) Query(OrgName string) (string, error) {
fmt.Println("\n Calling query method")
// Prepare arguments
var args []string
args = append(args, OrgName)
response, err := setup.client.Query(channel.Request{
ChaincodeID: setup.ChainCodeID,
Fcn: "invoke",
Args: [][]byte{[]byte("query"), []byte(args[0])}})
if err != nil {
return "", fmt.Errorf("failed to query: %v", err)
}
fmt.Println("\n Query chaincode ended")
return string(response.Payload), err
}
查询链码会导致以下错误:
紧急:运行时错误:无效的内存地址或nil指针取消引用
[信号SIGSEGV:细分违规代码= 0x1 addr = 0x8 pc = 0x9e17e0]
goroutine 1 [运行中]: github.com/hyperledger/fabric-sdk-go/pkg/client/channel.(*Client).Query(0x0,0xdb43d4,0x9,0xdb14ef,0x6,0xc00016ff80,0x2,0x2,0x0,0x0,...) /home/alpha/GoWorkspace/src/github.com/hyperledger/fabric-sdk-go/pkg/client/channel/chclient.go:97 + 0xc0 github.com/hyperledger/myproject/sdk.(*FabricSetup).Query(0xc000179ea8,0xdb0f3d,0x6,0x0,0xdbbe50,0x13,0xdb43cb)> /home/alpha/GoWorkspace/src/github.com/hyperledger/myproject/sdk /query.go:17 + 0x2d4 main.main() /c/Projects/Go/src/github.com/hyperledger/myproject/main.go:79 + 0x176
setup.go:用于创建频道,安装和实例化链码的文件
import packages
type FabricSetup struct {
ConfigFile string
OrgID string
OrdererID string
ChannelID string
ChainCodeID string
initialized bool
ChannelConfig string
ChaincodeGoPath string
ChaincodePath string
OrgAdmin string
OrgName string
UserName string
client *channel.Client
admin *resmgmt.Client
adminIdentity *msp.SigningIdentity
sdk *fabsdk.FabricSDK
event *event.Client
}
// Initialize reads the configuration file and sets up the client, chain and event hub
func (setup *FabricSetup) Initialize() error {
// Step 1: creates the channel and updates all of the anchor peers for all orgs
identityManagerClientContext := setup.sdk.Context(fabsdk.WithUser(setup.OrgAdmin), fabsdk.WithOrg(setup.OrgName))
if err != nil {
return errors.WithMessage(err, "failed to load Admin identity")
}
fmt.Printf("\n Step 2.a: Value of identityManagerClientContext is: ", identityManagerClientContext)
// Channel management client is responsible for managing channels (create/update channel)
chMgmtClient, err := resmgmt.New(identityManagerClientContext)
if err != nil {
return errors.WithMessage(err, "failed to create channel management client from Admin identity")
}
setup.admin = chMgmtClient
mspClient, err := mspclient.New(setup.sdk.Context(), mspclient.WithOrg(setup.OrgName))
if err != nil {
return errors.WithMessage(err, "failed to create MSP client")
}
adminIdentity, err := mspClient.GetSigningIdentity(setup.OrgAdmin)
if err != nil {
return errors.WithMessage(err, "failed to get admin signing identity")
}
setup.adminIdentity = &adminIdentity
fmt.Println("Initialization Successful")
setup.initialized = true
return nil
}
// CreateChannel for creating channel between the Organizations
func (setup *FabricSetup) CreateChannel() error {
req := resmgmt.SaveChannelRequest{
ChannelID: setup.ChannelID,
ChannelConfigPath: setup.ChannelConfig,
SigningIdentities: []msp.SigningIdentity{*setup.adminIdentity},
}
txID, err := setup.admin.SaveChannel(req, resmgmt.WithOrdererEndpoint(setup.OrdererID))
if err != nil || txID.TransactionID == "" {
return errors.WithMessage(err, "failed to save channel")
}
fmt.Println("Channel created")
return nil
}
// joins all peers in all of the given orgs to the given channel
func (setup *FabricSetup) JoinChannel() error {
// Make admin user join the previously created channel
if err := setup.admin.JoinChannel(
setup.ChannelID,
resmgmt.WithRetry(retry.DefaultResMgmtOpts),
resmgmt.WithOrdererEndpoint(setup.OrdererID)); err != nil {
return errors.WithMessage(err, "failed to make admin join channel")
}
fmt.Println("Channel joined")
return nil
}
// InstallCC to install and instantiate the chaincode
func (setup *FabricSetup) InstallCC() error {
// Create the chaincode package that will be sent to the peers
ccPkg, err := packager.NewCCPackage(setup.ChaincodePath, setup.ChaincodeGoPath)
if err != nil {
return errors.WithMessage(err, "failed to create chaincode package")
}
fmt.Println("ccPkg created")
// Install example cc to org peers
installCCReq := resmgmt.InstallCCRequest{
Name: setup.ChainCodeID,
Path: setup.ChaincodePath,
Version: "1.0", //chaincode version. first version of chaincode
Package: ccPkg,
}
_, err = setup.admin.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
if err != nil {
return errors.WithMessage(err, "failed to install chaincode")
}
fmt.Println("Chaincode installed")
return nil
}
// InstantiateCC for instantiating the chaincode
func (setup *FabricSetup) InstantiateCC() error {
// Set up chaincode policy
ccPolicy := cauthdsl.SignedByAnyMember([]string{"Seller", "Buyer"})
fmt.Println("Value of ccPolicy is: ", ccPolicy)
resp, err := setup.admin.InstantiateCC(setup.ChannelID, resmgmt.InstantiateCCRequest{
Name: setup.ChainCodeID,
Path: setup.ChaincodeGoPath,
Version: "1.0",
Args: [][]byte{[]byte("init"), []byte("Seller"), []byte("100"), []byte("Buyer"), []byte("200")},
//Args: [][]byte{[]byte("init")},
Policy: ccPolicy,
})
if err != nil || resp.TransactionID == "" {
return errors.WithMessage(err, "failed to instantiate the chaincode")
}
fmt.Println("Chaincode instantiated")
// Channel client is used to query and execute transactions
clientContext := setup.sdk.ChannelContext(setup.ChannelID, fabsdk.WithUser(setup.UserName))
setup.client, err = channel.New(clientContext)
if err != nil {
return errors.WithMessage(err, "failed to create new channel client")
}
fmt.Println("Channel client created")
// Creation of the client which will enables access to our channel events
setup.event, err = event.New(clientContext)
if err != nil {
return errors.WithMessage(err, "failed to create new event client")
}
fmt.Println("Event client created")
fmt.Println("Chaincode Installation & Instantiation Successful")
return nil
}
// CloseSDK to close the sdk connection
func (setup *FabricSetup) CloseSDK() {
setup.sdk.Close()
}
main.go文件:调用此文件中的所有方法
func initializeChannelAndCC(fSetup sdk.FabricSetup) {
err := fSetup.CreateChannel()
if err != nil {
fmt.Printf("Unable to create channel: %v\n", err)
}
err = fSetup.JoinChannel()
if err != nil {
fmt.Printf("Unable to join channel: %v\n", err)
}
err = fSetup.InstallCC()
if err != nil {
fmt.Printf("Unable to install the chaincode: %v\n", err)
}
err = fSetup.InstantiateCC()
if err != nil {
fmt.Printf("Unable to instantiate the chaincode: %v\n", err)
}
}
func main() {
fSetup := sdk.FabricSetup{
OrdererID: "orderer.mytrade.com",
ChannelID: "mychannel",
ChannelConfig: "/c/Projects/Go/src/github.com/hyperledger/myproject/network/channel-artifacts/channel.tx",
ChainCodeID: "myproject",
ChaincodeGoPath: "/c/Projects/Go",
ChaincodePath: "github.com/hyperledger/myproject/chaincode/",
OrgAdmin: "Admin",
OrgName: "Seller",
ConfigFile: "config.yaml",
UserName: "User1",
}
err := fSetup.Initialize()
if err != nil {
fmt.Printf("Unable to initialize the Fabric SDK: %v\n", err)
return
}
defer fSetup.CloseSDK()
initializeChannelAndCC(fSetup)
response, err := fSetup.Query("Seller")
if err != nil {
fmt.Printf("Unable to query the chaincode: %v\n", err)
} else {
fmt.Printf("Response from the query: %s\n", response)
}
}
客户端日志记录(设置为调试模式)。这些日志非常庞大,因此共享链接ClientLogs
请帮助。
type SimpleChaincode struct {
}
// Init method: one time initialisation
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ex02 Init")
_, args := stub.GetFunctionAndParameters()
var A, B string // Entities
var Aval, Bval int // Asset holdings
var err error
if len(args) != 4 {
return shim.Error("Incorrect number of arguments. Expecting 4")
}
test := strings.Join(args, ", ")
fmt.Println("Value of args is: ", test)
// Initialize the chaincode
A = args[0]
Aval, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
B = args[2]
Bval, err = strconv.Atoi(args[3])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
fmt.Printf("A = %s, Aval = %d, B = %s, Bval = %d\n", A, Aval, B, Bval)
// Write the state to the ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
// Invoke method: used to sedn the request to the various custom methods
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ex02 Invoke")
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
// Make payment of X units from A to B
return t.invoke(stub, args)
} else if function == "delete" {
// Deletes an entity from its state
return t.delete(stub, args)
} else if function == "query" {
// the old "Query" is now implemtned in invoke
return t.query(stub, args)
}
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}
// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A, B string // Entities
var Aval, Bval int // Asset holdings
var X int // Transaction value
var err error
fmt.Println("Value of args in invoke is: ", strings.Join(args, ", "))
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
A = args[0]
B = args[1]
// Get the state from the ledger
// TODO: will be nice to have a GetAllState call to ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
return shim.Error("Failed to get state")
}
if Avalbytes == nil {
return shim.Error("Entity not found")
}
Aval, _ = strconv.Atoi(string(Avalbytes))
Bvalbytes, err := stub.GetState(B)
if err != nil {
return shim.Error("Failed to get state")
}
if Bvalbytes == nil {
return shim.Error("Entity not found")
}
Bval, _ = strconv.Atoi(string(Bvalbytes))
// Perform the execution
X, err = strconv.Atoi(args[2])
if err != nil {
return shim.Error("Invalid transaction amount, expecting a integer value")
}
Aval = Aval - X
Bval = Bval + X
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state back to the ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
A := args[0]
// Delete the key from the state in ledger
err := stub.DelState(A)
if err != nil {
return shim.Error("Failed to delete state")
}
return shim.Success(nil)
}
// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
fmt.Println("Inside query method")
var A string // Entities
var err error
fmt.Println("\value of args in query method is: ", strings.Join(args, ", "))
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
}
A = args[0]
// Get the state from the ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
return shim.Error(jsonResp)
}
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
fmt.Printf("Query Response:%s\n", jsonResp)
return shim.Success(Avalbytes)
}
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
运行时错误之后,我使用以下命令登录到peer0.seller.mytrade.com
cli
docker exec -it cli bash
并运行peer chaincode query -C mychannel -n myproject -c '{"Args":["query","Seller"]}'
命令来查询链码,我得到了结果Seller = 100
。
在运行peer chaincode query
命令之前,dev-peer0.seller.mytrade.com
容器已丢失。仅存在容器dev-peer1.seller.mytrade.com
。但是在peer chaincode query
cli上执行peer0.seller.mytrade.com
命令之后,就产生了链码容器。由于在卖方的两个对等方上都调用了链码,因此两个容器都应该在那儿。
我还添加了20s延迟,因为我认为docker需要一些时间来创建容器。但这没用。