Hyperledger Fabric chain code development practice log

1. Overview of chain code structure

Here, the development of chain code uses Go language. Therefore, we need to simply learn Go language first. It is a lightweight language. Interestingly, it has its own channel and can be concurrent, which is very suitable for the development of large-scale distributed systems.
To Start the chain code, you must call the Start function in the shim package. The parameter of this function is a Chaincode interface type. There are two methods in the Chaincode interface type, Init and Invoke, which are two very important methods in the development of chain code:

  • Init: called when the chain code is instantiated or upgraded to complete data initialization;
  • Invoke: called when updating or querying the ledger data status in the proposal transaction.

In actual development, you need to define a structure and rewrite Init and Invoke methods to complete relevant functions. Let's take a look at the necessary structure of a chain code:

package main //The name of the package written

import (
        "fmt"
        "github.com/hyperledger/fabric/core/chaincode/shim"
        "github.com/hyperledger/fabric/protos/peer"
)//Introduce necessary packages

type HelloChaincode struct{}//Define a structure

func main() {
        err := shim.Start(new(HelloChaincode))
        if err != nil {
                fmt.Printf("Chain code start failed: %v", err)
        }
}//Main function, call shim Start party sends start chain code

func (t *HelloChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response{
       
}

func (t *HelloChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response{        fun, args := stub.GetFunctionAndParameters()
       
}

2. Be familiar with chain code related API

It is mainly the API provided by the shim package, which is divided into five categories:

  1. Parameter parsing API: used to obtain parameters
  2. Ledger data status operation API: query and update ledger data
  3. Transaction information acquisition API: obtain the submitted transaction information
  4. Event handling API: related to event handling
  5. API for private data operations: specifically for private data operations

There are still a large number of APIs, most of which are used to obtain relevant information. You can take a closer look when you have time. There are several main APIs used in the primary stage:

  • GetFunctionAndParameters()(function string, params []string) returns the name of the called function and the parameter list
  • GetStringArgs()[]string returns the parameter list directly
  • GetState(key string)([]byte,error) queries the data status according to the specified key value
  • PutState(key string,value []byte)error saves the corresponding value to the account book according to the specified key

3. The chain code realizes Hello World

3.1 chain code development

  1. Enter the chaincode directory, create a folder named hello, and then create and edit the chain code file:
sudo mkdir hello && cd hello
sudo vim hello.go
  1. Import chain code dependent package:
package main

import (
			"fmt"
			"github.com/hyperledger/fabric/core/chaincode/shim"
			"github.com/hyperledger/fabric/protos/peer"
		)
  1. Write main function:
func main() {
			err := shim.Start(new(HelloChaincode))
			if err != nil {
				fmt.Printf("Chain code start failed: %v", err)
			}
}
  1. Custom structure:
type HelloChaincode struct{}
  1. Rewrite the Init method. Its function is to initialize the data state. A simple logical step is as follows:
  • Obtain parameters and judge whether the parameters are legal;
  • Call the PutState function to write the status into the account book;
  • Whether there is a write error;
  • Finally, call the Success function to return the Success status.
func (t *HelloChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response{
		    fmt.Println("Start instantiating chain code")
			_, args := stub.GetFunctionAndParameters()
			if len(args) != 2 {
				return shim.Error("Wrong number of parameters specified")
			}
			fmt.Println("Save data")
			err := stub.PutState(args[0],[]byte(args[1]))
			if err !=nil{
				return shim.Error("An error occurred while saving data")
			}
			fmt.Println("Instantiation succeeded")
			return shim.Success(nil)
}

Note the GetFunctionAndParameters() function, where the parameter form is: "args": ["init", "Hello", "Wzh"). The function obtains the called function "init" and the passed in parameters "Hello", "Wzh", so it is written as, Args can also be replaced by GetStringArgs() function to directly obtain the following parameters.

  1. Override the Invoke method. Its simple logic is:
  • Obtain parameters and judge whether the parameters are legal;
  • Use the key value to obtain the status;
  • Complete the function of the called function;
  • Return data status or success status.
func (t *HelloChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response{	fun, args := stub.GetFunctionAndParameters()
			if fun == "query"{
				return query(stub,args)
			}
			return shim.Error("Illegal operation, the specified function cannot be realized")
}

func query(stub shim.ChaincodeStubInterface,args  []string) peer.Response{
			if len(args) !=1{
				return shim.Error("The specified parameter is wrong. You must and can only specify the corresponding parameter Key")
			}
			result,err :=stub.GetState(args[0])
			if err !=nil {
				return shim.Error("According to the specified" +args[0] +"An error occurred while querying the data")
			}
			if result ==nil {
				return shim.Error("According to the specified" +args[0] +"No corresponding data found")
			}
			return shim.Success(result)
}

This code is very simple and clear. I won't repeat it.

3.2 chain code test

The link of chain code test comes again. The specific process is in the previous log. Only the code is attached below:

cd chaincode-docker-devmode
sudo docker-compose -f docker-compose-simple.yaml up -d

Open terminal 2 window:

sudo docker exec -it chaincode bash
cd hello
go build
CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=hellocc:0 ./hello

Open terminal 3 window:

sudo docker exec -it cli bash,
peer chaincode install -p chaincodedev/chaincode/hello -n hellocc -v 0
peer chaincode instantiate -n hellocc -v 0 -c '{"Args":["init","Hello","Wzh"]}' -C myc
peer chaincode query -n hellocc  -c '{"Args":["query","Hello"]}' -C myc

Finally, the query should get Wzh (that is, the content assigned by the Hello key)

Tags: Go Database

Posted by pmcconaghy on Mon, 09 May 2022 12:16:02 +0300