The Chaincode is written in the go language and implements the defined interface. Other languages, such as Java, are also supported. The ledger state can be initialized and managed by application volume Transaction,chaincode.
A chaincode-created ledger state is independent and cannot be accessed directly by other chaincode. With the appropriate permission, Chaincode can invoke other Chaincode under the same network to access its ledger state.
Next, let's look at Chaincode from the perspective of Chaincode developers. Let's look at each method of the Chaincode Shim API in a Chaincode case.
1.Chaincode API
Each chaincode needs to implement the Chaincode interface, which is used to respond to received transaction. When Chaincode receives the instantiate or upgrade transaction, the Init method is invoked so that Chaincode can perform any necessary initialization, including application state initialization. Invokes the Invoke method when Chaincode receives the invoke transaction, which is used to process the transaction proposal.
The other interfaces in the "Shim" API are chaincodestubinterface for accessing and changing ledger, and for calling between Chaincode.
In this tutorial, we will demonstrate the use of these APIs by implementing simple Chaincode applications, which manage simple "assets".
2. Simple Asset Chaincode
Our application is a basic sample chaincode for creating assets on ledger (key-value pairs).
It is recommended to use Vscode for Go code writing,
Open the terminal and run the following command:
sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make
sudo apt-get update
sudo apt-get install Ubuntu-make
If it is already installed, run the following command:
Umake Web Visual-studio-code
Please note that during the installation process, you will be asked to give the path Insatllation package. After that, it asks to submit your permission to install the Visual Studio code. Please press ' to install (' to indicate acceptance terms and conditions ').
Set Gopath
Vscode when installing the Go plug-in prompts Gopath not set error, open Launch.json in env
Install Vscode go
Search the Vscode App Store for go, click Install.
2.1 Select the location of the code
The preferred need is to determine that the go environment is installed and properly configured.
For the sake of simplicity, we use the following command:
Mkdir-p $GOPATH/src/asset && cd $GOPATH/src/asset
Next, we create the source file
Touch Asset.go
2.2 Introduction Package
Each Chaincode implements the Chaincode interface
Package main
Import (
"FMT"
"Github.com/hyperledger/fabric/core/chaincode/shim" "
github.com/ Hyperledger/fabric/protos/peer "
)
2.3 Initialization of Chaincode
Our class is called Simpleasset.
Type simpleasset struct {
}
Next, we have init functions beforehand
The Init is called during Chaincode instantiation to initialize any data.
Func (t *simpleasset) Init (stub shim. Chaincodestubinterface) Peer. Response {
}
Note: Chaincode upgrade also calls this function. When a chaincode is to be upgraded, make sure that the INIT function is properly modified. If there is nothing to migrate, or nothing to initialize at the time of the upgrade, the null init function needs to be provided.
Next, we call the Chaincodestubinterface.getstringargs method to get the parameters required in init and check the validity of the parameters. The parameter we expect to get is a key-value pair.
The Init is called during Chaincode instantiation to initialize any
//data. Note that Chaincode upgrade also calls this function to reset
//or to migrate data, so is careful to avoid a scenario where you
//inadvertently clobber your ledger ' s data!
Func (t *simpleasset) Init (stub shim. Chaincodestubinterface) Peer. Response {
//Get the args from the transaction proposal
args: = Stub. Getstringargs ()
If Len (args)!= 2 {return
shim. Error ("Incorrect arguments. Expecting a key and a value ")
}
}
Next, as our call is valid, we will store the initial state on the ledger. To implement state storage, we will call the Chaincodestubinterface.putstate method and enter the key value as a parameter. Assuming that everything is working properly, a peer is returned. Response object, surface initialization succeeded.
The Init is called during Chaincode instantiation to initialize any
//data. Note that Chaincode upgrade also calls this function to reset
//or to migrate data, so is careful to avoid a scenario where you
//inadvertently clobber your ledger ' s data!
Func (t *simpleasset) Init (stub shim. Chaincodestubinterface) Peer. Response {
//Get the args from the transaction proposal
args: = Stub. Getstringargs ()
If Len (args)!= 2 {return
shim. Error ("Incorrect arguments. Expecting a key and a value ")
}
//Set up any variables or assets this by calling stub. Putstate ()
//We store the key and the value on the ledger
err: = Stub. Putstate (Args[0], []byte (Args[1]))
If Err!= nil {return
shim. Error (FMT. Sprintf (' Failed to create asset:%s ', args[0])
} return
shim. Success (nil)
}
2.4 Call Chaincode
First, add the Invoke function signature
The Invoke is called/transaction on the Chaincode. Each transaction are
//either a ' get ' or a ' set ' on the asset created by Init function. The ' Set '
//may create a new asset by specifying a new Key-value pair.
Func (t *simpleasset) Invoke (stub shim. Chaincodestubinterface) Peer. Response {
}
Just like the init function above, we need to get the parameters through Chaincodestubinterface. The arguments to the invoke function are the names that need to invoke the Chaincode application. In our example, our application has two simple functions set and get, allowing asset values to be set, while allowing for the current state to be obtained. We first call chaincodestubinterface.getfunctionandparameters to get the function name and parameters for the Chaincode application.
The Invoke is called/transaction on the Chaincode. Each transaction are
//either a ' get ' or a ' set ' on the asset created by Init function. The Set
//May create a new asset by specifying a new Key-value pair.
Func (t *simpleasset) Invoke (stub shim. Chaincodestubinterface) Peer. Response {
//Extract the function and args from the transaction proposal
FN, args: = Stub. Getfunctionandparameters ()
}
We then set the set and get function names and call these Chaincode application functions to return an appropriate response via shim. The error function will serialize a response to a GRPC protobuf message.
The Invoke is called/transaction on the Chaincode. Each transaction are
//either a ' get ' or a ' set ' on the asset created by Init function. The Set
//May create a new asset by specifying a new Key-value pair.
Func (t *simpleasset) Invoke (stub shim. Chaincodestubinterface) Peer. Response {
//Extract the function and args from the transaction proposal
FN, args: = Stub. Getfunctionandparameters ()
var result string
var err error
If fn = ' Set ' {result
, err = set (stub, args) c9/>} else {result
, err = get (stub, args)
}
If err!= nil {return
shim. Error (Err. Error ())
}//Return of result as
Success payload return
Shim. Success ([]byte (Result)
}
2.5 Implement Chaincode Application
Our Chaincode application implements two functions that can be invoked through invoke. Next, implement these functions. As we mentioned above, I use the chaincodestubinterface.putstate and chaincodestubinterface.getstate of the Chaincode Shim API to access the state of access.
Set stores the asset (both key and value) on the ledger. If the key exists,//It'll override the value with the new one Func set (stub shim. Chaincodestubinterface, args []string) (string, error) {if Len (args)!= 2 {return "", FMT. Errorf ("incorrect arguments.") Expecting a key and a value "} Err: = Stub. Putstate (Args[0], []byte (Args[1])) If Err!= nil {return "", FMT. Errorf ("Failed to set Asset:%s", Args[0])} return args[1], nil}//Get returns the value of the specified Asse T key func get (stub shim. Chaincodestubinterface, args []string) (string, error) {if Len (args)!= 1 {return "", FMT. Errorf ("incorrect arguments.") Expecting a key ")} value, Err: = Stub. GetState (Args[0]) If Err!= nil {return "", FMT. Errorf ("Failed to get asset:%s with Error:%s", Args[0], err)} if value = = Nil {return "", FMT. Errorf (' Asset not found:%s ', args[0])} return string (value), nil}
2.6 Merging the above code
Package main import ("FMT" "Github.com/hyperledger/fabric/core/chaincode/shim" "Github.com/hyperledger/fabr Ic/protos/peer ")//Simpleasset implements a simple chaincode to manage an asset type simpleasset struct {}//Init is Called during Chaincode instantiation to initialize any//data.
Note that Chaincode upgrade also calls the This function to reset//to migrate data. Func (t *simpleasset) Init (stub shim. Chaincodestubinterface) Peer. Response {//Get the args from the transaction proposal args: = Stub. Getstringargs () If Len (args)!= 2 {return shim. Error ("Incorrect arguments. Expecting a key and a value ")}//Set up any variables or assets this by calling stub. Putstate ()//We store the key and the value on the ledger err: = Stub. Putstate (Args[0], []byte (Args[1])) If Err!= nil {return shim. Error (FMT. Sprintf (' Failed to create asset:%s ', args[0])} return shim. Success (NIL)}//Invoke is Called/Transaction on the Chaincode. Each transaction are//either a ' get ' or a ' set ' on the asset created by Init function.
The Set//may create a new asset by specifying a new Key-value pair. Func (t *simpleasset) Invoke (stub shim. Chaincodestubinterface) Peer. Response {//Extract the function and args from the transaction proposal FN, args: = Stub. Getfunctionandparameters () var result string var err error if fn = ' Set ' {result, err = set (stu b, args)} else {//assume ' get ' even if FN be nil result, err = get (stub, args)} If Err!= nil {return shim. Error (Err. Error ())}//Return of result as success payload return shim. Success ([]byte)}//Set stores the asset (both key and value) on the ledger. If the key exists,//It'll override the value with the new one Func set (stub shim. Chaincodestubinterface, args []string) (string, error) {if Len (args)!= 2 {return "",Fmt. Errorf ("incorrect arguments.") Expecting a key and a value "} Err: = Stub. Putstate (Args[0], []byte (Args[1])) If Err!= nil {return "", FMT. Errorf ("Failed to set Asset:%s", Args[0])} return args[1], nil}//Get returns the value of the specified Asse T key func get (stub shim. Chaincodestubinterface, args []string) (string, error) {if Len (args)!= 1 {return "", FMT. Errorf ("incorrect arguments.") Expecting a key ")} value, Err: = Stub. GetState (Args[0]) If Err!= nil {return "", FMT. Errorf ("Failed to get asset:%s with Error:%s", Args[0], err)} if value = = Nil {return "", FMT. Errorf (' Asset not found:%s ', args[0])} return string (value), nil}//main function starts up the Chaincode in The container during instantiate func main () {if err: = shim. Start (New (Simpleasset)); Err!= Nil {fmt. Printf ("Error starting Simpleasset Chaincode:%s", err)}}
2.7 Build Chaincode
Compiling Chaincode
Go get-u--tags nopkcs11 github.com/hyperledger/fabric/core/chaincode/shim go build
--tags NOPKCS11
Next Test Chaincode
2.8 Using DEV Mode test
Generally speaking, peer starts and holds chaincode. In development mode, however, Chaincode is created and started by the user. This pattern is useful in the development phase of the chain code during the fast Code/build/Run/debug cycle turnaround period.
We start a "development model" of a simple development network by leveraging the pre generated order and channel artifacts. As a result, users can immediately compile chaincode and call functions.
3. Installation of Hyberledger Fabric sample
Please install the Hyberledger Fabric sample first.
Enter Fabric-samples and Chaincode-docker-devmode directory
CD Chaincode-docker-devmode
4. Download Docker image
We need four Docker mirrors for development mode to allow Docker compose Script, if you have already installed the Fabric-samples warehouse clone and follow the instructions to download the platform-specific-binaries, then you should follow Docker mirroring locally. Enter the docker images command to display the Docker image. Should be able to see the following:
Docker images REPOSITORY TAG IMAGE ID CREATED SIZE Hyperledger/fabric-tools latest e09f38f8928d 4 hours ago 1.32 GB H Yperledger/fabric-tools x86_64-1.0.0-rc1-snapshot-f20846c6 e09f38f8928d 4 hours ago 1.32 GB Hyperle Dger/fabric-orderer latest 0df93ba35a25 4 hours ago 179 MB HYPERLEDGER/FA Bric-orderer x86_64-1.0.0-rc1-snapshot-f20846c6 0df93ba35a25 4 hours ago 179 MB Hyperledger/fabric-pe ER latest 533aec3f5a01 4 hours ago MB hyperledger/fabric-peer X86_64-1.0.0-rc1-snapshot-f20846c6 533aec3f5a01 4 hours ago MB hyperledger/fabric-ccenv late St 4b70698a71d3 4 hours ago 1.29 GB Hyperledger/fabric-ccenv x86_64-1.0 .0-rc1-snapshot-f20846c6 4b70698a71d3 4 hours ago 1.29 GB
5. Start Network
Docker-compose-f Docker-compose-simple.yaml up
The above code starts the network that includes Singlesamplemspsolo Orderer profile, and initiates the development mode of peer. This launches the other two containers, one is the chaincode environment and the CLI interacting with the Chaincode. Create and join channel commands in the CLI container, so we can start Chaincode calls.
6.build and Boot Chaincode
Docker exec-it Chaincode Bash
Into the container,
root@d2629980e76b:/opt/gopath/src/chaincode#
Next, compile the Chaincode
CD Asset Go Build
Run Chaincode Now:
core_peer_address=peer:7051 core_chaincode_id_name=mycc:0. /asset
Peer started the Chaincode, and Chaincode logs indicate that peer successfully registered Chaincode. This stage Chaincode does not have any association with any channel. This is done in subsequent steps that use the instantiation command.
7. Use of Chaincode
Even now in--peer-chaincodedev mode, you still need to install chaincode so that the lifecycle Chaincode can be checked properly.
We use the CLI container to invoke these methods
Docker exec-it CLI Bash
Peer Chaincode install-p chaincodedev/chaincode/asset-n mycc-v 0 Peer Chaincode instantiate-n mycc-v 0-c
' {' Args ": [" a "," Ten "]} '-C MYC
Next, change the value of a to 20.
Peer Chaincode invoke-n mycc-c ' {Args ': [' Set ', ' a ', ' ']} '-C MYC
Last Query
Peer Chaincode query-n mycc-c ' {Args ': [' query ', ' a ']}