This extends on the network from byfn by adding a new Organization to the channel. Chaincode updates are handled by an organization admin and not a chaincode or application developer
Environment Setup
First we set up the environment by using the byfn.sh script, we do this by first clearning up any previous artifacts, generating new artifacts, and launching the network as follows:
If you run into a Permission denied error, run it again with sudo
Add Org3 to the Channel
Newt we should be able to add Org3 to the channel with the eyfn.sh script as follows
We can also make use of the script to configure our network with a few different options with
And then
Once we are done, we can look at the logs and then run the following script to bring down the network
Add Org3 to the Channel Manually
Before starting, modify the docker-compose-cli.yaml in the first-network directory to set the FABRIC_LOGGING_SPEC to DEBUG
And do the same for the docker-compose-org3.yaml file
Now, bring up the initial network with the following commands:
This will get us to the same network state as before we executed the ./eyfn.sh up command
Generate the Org3 Crypto Material
In a new terminal cd into the org3-artifacts directory and generate the crypto material for Org3 using the org3-crypto.yaml and the configtx.yaml files
This command reads the org3-crypto.yaml file and uses cryptogen to generate the keys and certificates for an Org3 CA and 2 Peers, the crypto material is then placed into the orypto-config subdirectory
Next we use the configtxgen tool to create the Org3 config material in JSON as follows
Now we have all the required material to update the channel
Prepare the CLI Environment
We will mak use of the configtxlator tool which provides a stateless REST API aside from the SDK as well as allows us to easily convert between different data representations/formats
First exec into the CLI container export the following variables
If you need to restart the CLI container, you will need to redefine the above variables (obviously)
Fetch the Configuration
Now that we have defined the two environment variables we can fetch the most recent config block for the channel. We will then save a binary protobuf channel configuration block to a config_block.pb file with the following command
The last line of the output should say something like
From here we can see that the most recent block is from the byfn script and it was when the script defined Org2, The following are the configurations we have done so far
Block 0 - Genesis Block
Block1 - Org 1 Anchor Peer update
Block 2 - Org 2 Anchor Peer update
Convert Config to JSON
We will now make use of the configxlator tool to decode the channel conifguration blok into JSON as well as strip away any metadata and creator signatures that are irrlevant to us as humans with the jq tool
Add the Org3 Crypto Material
Up until this point the steps for making any config update will be the same, from here the steps are specific to adding a channel
Now that we have the Channel config as JSON we can use jq to append the org3.json definition and save it as modified_config.json
And thereafter we translate the config.json and modified_config.json to protobufs config.pb and modified_config.pb respectively so we can calculate the delta between the two configs
Then we can calculate the deltas
The file we just genreated org3_update.pb contains the Org3 definitions and is the definition of the deltas
Before submiting to the channel, we need to add some headers and additional content around the JSON file, we can do that by first getting a JSON version of our deltas
And wrapping it in some additional data and adding the meta back with jq
Lastly, we will convert the final JSON deltas into a protobuf file as follows
Sign and Submit the Update
We have the updated proto in the org3_update_in_envelope.json file in the conainerm however we need signatures from the required admin users before the conffig change can we written to the ledger
The modification policy is set to the default value of MAJORITY, since we have two peers, this means they oth need to sign the change otherwise the ordering service will reject the transaction
We can first sign the update as Org1 Admin as follows (since the CLI is bootstrapped with the Org1 MSP Material) by executing the following command
Next we switch to Org2 by changing our environment credentials and running the peer channel update command
Note that realistically a single container would not have all the network’s crypto material
Export the Org2 environment variables
And then sign the update with this peer as well
Cofiguring Leader Election
The default leader mode is dynamic for new peers. New peers are bootstrapped with the genesis block that does not contain information about the Org they are in. New peers are unable to verify blocks until they get a channel configuration transaction, they therefore must have a leader mode in order to receive blocks from the Ordering service
Static:
Dynamic:
Join Org3 to the Channel
Until this point the channel config has been updated to include Org3, meaning that new peers on Org3 can jon the channel mychannel
We can set up Org3 by using the docker compose file for it
And then we can exec into it with the following
And export the key variables
Next we can send a call to the ordering service to retrieve the block we just added
Note that the 0 we pass to the above command will retrieve the Genesis block and not the latest block in the chain
Next we can join the peer to the channel using the genesis block as follows
We can then add a second peer to the block with:
Upgrade and Invoke Chaincode
The new chaincode policy has been put in place to include Org3, we can install the updated chaincode on Org3 with the following:
And then from the original CLI container we can install the chaincode onto peer0.org1 and peer0.org2 with the following
Now that the chaincode has been installed we can upgrade the chaincode and specify the new endorsement policy for transactions. Furthermore we can see that we are passing the initialize command with a few arguments
Next we can query the chaincode, invoke it, and query it again to see that it works as follows
Chaincode for Developers
Chaincode is a program in Go, Node or Java that implements the prescribed Chaincode Interface. It runs in a secured docker container isolated from the peer process and intiializes and manages ledger state by way of transactions
Chaincode handles business logic agreed by members of a network, similar to a smart contract. Chaincode can be invoked to update or query the ledger, and with the correct permissions even invoke other chaincode
The Chaincode API
Any chaincode program must implement the Chaincode interface, whose methods are called in response to received transactions. Particularly the Init method is called when a chaincode receives an instantiate or upgrade transaction
The other interface available is the ChaincodeStubInterface and allows chaincodes to access and modify the ledger and make invocations to other chaincode
Simple Asset Chaincode
We will make use of a simple chaincode built with Go (I will look at implementing this with Node as well, but the documentation uses Go for the time being)
Firstly, you will need to install Go and create the following directories (For more info on Go and how the Go file system needs to look - check out the notes on that here
The Go Installation Instructions for Fabric can be found here
Make the directory in your Go workspace go/src/sacc. You can easily cd to this by using the $GOPATH environment variable, in the Go workspace, make the directory src/sacc in which we can add the chaincode
Housekeeping
The chaincode file will need to import the necessary packages and have a struct which can define the asset
Initialization
We need to provide the Init function, this is called when te chaincode is initialized or when chaincode is upgraded. When writing a chaincode upgrade be sure to modify the Init function to be empty if there is no migration that needs to be done
Our Init function will be defined as follows:
It will make use of the GetStringArgs function, since we are expecting a key-value pair, we will need to have two arguments so we will check for that
Then we will store the state in the ledger using the PutState function with the key and value, and if that went well we will return a peer.Response
Invoking the Chaincode
Invoke is called per transaction, and may either be a get or set method. set will create a new asset by specifying the key-value pair
Once again, we need to extract the argumets from the ChaincodeStubInterface, our application has a get and a set function that allow the value of an asset to be set, or its current value to be retrieved. We first call the GetFunctionAndParameters to get the function name and params
Next, we will identify if the function is get or set and will call the respective functions, we do this simply as follows
Implementing the Chaincode Functionality
Next we can define the chaincode implementation by defining the get and set functions. We will make use of the PutState and GetState functions to do this
Starting the Chaincode
Lastly, we need to implement the main method that will call the shim.Start function
Final Chaincode
The overall chaincode will be as follows
Build the Chaincode
We can compile the code with the following
Test the Code
We can test the chaincode with the fabric-samples/docker-devmode folder. For this we will need 3 terminals
Terminal 1 - Start the Network
Terminal 2 - Build and Start the Chaincode
Then run the chaincode with
Terminal 3 - Use the Chaincode
Note on the Instantiation Method
Note that the instantiation method in the official documentation for this tutorial does not make us of the init argument that should be passed in (This may result in it failing when using something like IBM Cloud Blockchain which by default passes in the init argument), for a better example of an Instantiation take a look at this page