我正在使用 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
这里链码被实例化,但 Input 标签显示 nil 值。是预期的吗?不是应该显示我用于实例化的值吗
查询链码
代码片段
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 }
对链码的这种查询导致以下错误:
恐慌:运行时错误:无效的内存地址或零指针取消引用
【信号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
clidocker 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
存在。但是 在cli上的peer chaincode query
命令导致链码容器之后。peer0.seller.mytrade.com
由于在卖方的两个对等方上调用了链码,因此两个容器都应该在那里。我还添加了 20 秒的延迟,因为我认为 docker 需要一些时间来创建容器。但它没有用。