AWS Database Blog

Add new members to a Hyperledger Fabric channel on Amazon Managed Blockchain

In the previous post in this series, you learned how to build a Hyperledger Fabric network using Amazon Managed Blockchain. After creating the network, you deployed a three-tier application that consisted of Fabric chaincode, a RESTful API, and a user interface application. The network you created was a single-member network, suitable for experimenting and learning the basics of Hyperledger Fabric.

However, a more robust test or production scenario might involve a multi-member decentralized network. Members in the network might represent real-world organizations that participate in a common business process and benefit from sharing data and collaborating with each other.

In this post, you add a new member to the Fabric network you created in part 1. You create the new member, provision a peer node for the new member, and join the peer to an existing channel. You can create the new member in a different AWS account, or in the same AWS account as the part 1 network. I use a different AWS account in this post, but either option works. After the new peer node has joined the channel, you check whether blocks are being replicated to the new peer, then you install chaincode and invoke transactions. Your peer node becomes a fully functioning node in the Fabric network, with the ability to endorse and validate transactions while maintaining its own copy of the Fabric ledger.

Architecture Overview

The outcome of following the steps in this post is a multimember network with two members, where each member is owned by a different AWS account. You can access the member owned by each account by using a Fabric client node or any Fabric client application running in a VPC in that account.

As seen in the following diagram, the Hyperledger Fabric ordering service, the member’s certificate authority (CA), and the member’s peers are managed by Managed Blockchain. They have their endpoints exposed to customer VPCs by using VPC endpoints. All network traffic between a customer VPC and the managed Fabric network occurs over the AWS backbone and is not exposed to the public internet.

Prerequisites: an existing Hyperledger Fabric network  on Managed Blockchain

You can find the steps to add a new member to an existing Fabric network in the same Git repository as for the previous blog post. The previous post has been updated with part 5. Before starting part 5, you should have a Hyperledger Fabric network running with at least one member. You can do this by completing part 1 in the previous post. Completing parts 1–4 also works, though parts 2–4 are not prerequisites for completing part 5.

Hyperledger Fabric channels

Before provisioning a new member, let’s review the purpose of Hyperledger Fabric channels. Channels are the mechanism by which members in a Fabric network communicate. Two or more members in the network join a channel. Those members then can transact privately on the channel without sharing their ledgers with other members in the same network. Channels therefore allow different combinations of members to share different types of information.

As mentioned in the previous blog post, a Hyperledger Fabric ledger consists of two parts: a journal that holds a cryptographically immutable transaction log (or “blockchain”) and a key-value store known as the world state that stores the current state of the ledger. The ledger is created by binding chaincode to a channel, and is physically present on each peer node joined to the channel. The implication is that a peer node that joins two channels would host two independent ledgers.

Part 5: Adding a new member to a Fabric network on Managed Blockchain

When adding a new member to an existing Fabric network, there are two scenarios to consider:

  1. The new member joins an existing channel where existing members are already collaborating and transacting. The existing members already maintain their own ledgers for this channel.
  2. The new member, together with existing members, create a new channel where they collaborate and transact.

The rest of this article focuses on scenario 1 above. Scenario 2 is covered in the readme file for part 5 in the Git repo. It is also explained in the Managed Blockchain documentation. Scenario 1 is more complex because the existing channel configuration has to be updated to include the new member.

Adding a new member to an existing Fabric network involves a number of steps. The new member is located in a different AWS account. The steps therefore involve cooperation between Fabric administrators in the existing account, where the Fabric network was originally created, and the new account, where the new member is created. Let’s call the existing account account A, and the new account account B. The steps are as follows:

  1. Account A invites account B to join the Fabric network.
  2. Account B creates a member in the Fabric network.
  3. Account B creates a peer node.
  4. Account B creates a Fabric client node.
  5. Account B prepares the Fabric client node and enrolls an identity.
  6. Account B shares the public keys for its member with account A.
  7. Account A creates an MSP folder for the new account B member.
  8. Account A creates a configtx.yaml file that includes the new account B member.
  9. Account A generates a channel configuration.
  10. Endorsing peers sign the new channel configuration.
  11. Account A updates the channel with the new configuration.
  12. Account A shares the genesis block for the channel with account B.
  13. Account B starts its peer node and joins the channel.
  14. Account B installs chaincode.
  15. Account B queries the chaincode.
  16. Account B invokes a transaction.
  17. Account A updates the endorsement policy for the chaincode on the channel.
  18. Account B installs the latest version of the chaincode.

Let’s walk through the purpose of each of the steps and understand the details. Further information on how to carry out each step can be found in the Git repo. Each step listed here has a matching step in the Git repo.

Step 1: Account A invites account B to join the Fabric network

In the Managed Blockchain preview, new members in other AWS accounts must be invited to join the Fabric network. The other AWS accounts must also be part of the Managed Blockchain preview. The Fabric administrator for account A invites another AWS account to join the Fabric network. In the Managed Blockchain console, select your Fabric network and choose the Invite account button. Enter the 12-digit AWS account number of the account you want to invite. You should see a confirmation message indicating your invitation has been sent successfully.

Step 2: Account B creates a member in the Fabric network

A user logged in to account B can view the invitation in the Managed Blockchain console. Clicking on the network name shows the details of the network that account B has been invited to join. Choose Create member to create a member in the network, and enter a unique member name, an administrator user name, and a password for the member. Make a note of the administrator user name and password because you need them later.

At this point, Managed Blockchain provisions a highly available Fabric CA for the new member.

Step 3: Account B creates a peer node

After your Fabric network and member have an ACTIVE status, it’s time to create a Fabric peer node. Each member on a network creates their own peer nodes, so select the member you created above and click the link to create a peer node. Select an instance type, the amount of storage for the node, and create the peer node. Like the ordering service and CA, each member’s peer nodes are managed by Managed Blockchain and can be accessed from your VPC by using a VPC endpoint.

At this stage, you have a Hyperledger Fabric network with a highly available ordering service. There are two members in the network, each with their own CA, and each containing a single peer.

Now, you need a way to interact with the new member in your Fabric network so that you can create channels, install chaincode, and invoke transactions. To do this, you create a Fabric client node in your VPC.

Step 4: Account B creates a Fabric client node

These steps are identical to those performed by account A when the Fabric network was originally created. As seen in the architectural diagram preceding, the Fabric components managed by Managed Blockchain are accessed through a Fabric client node that you provision in a VPC in your account. The Fabric client node hosts the open-source Fabric CLI and enables you to interact with your Fabric network by using the VPC endpoint.

You use AWS CloudFormation to provision three items. These are a new VPC in account B, an EC2 instance configured as your Fabric client node, and the VPC endpoint to communicate with your Fabric network.

Make sure that you have completed the prerequisites for account B, as specified in the Git repo. Then follow step 4 to provision your Fabric client node.

Step 5: Account B prepares the Fabric client node and enrolls an identity

An admin identity was created for you when you created the member in step 2. You also stored the admin user name and password, which is used in this step to enroll the admin user. Enrollment in Fabric is the process that generates the Membership Service Provider (MSP) folder. This folder contains your enrollment certificate, your private key, and the root and intermediate certificates signed by your CA. You use these to authenticate to Managed Blockchain by signing all operations with the private key in your MSP. You use the admin identity to administer the Fabric network and perform tasks such as creating channels and instantiating chaincode.

Step 6: Account B shares the public keys for its member with account A

All Fabric operations (including transaction proposal endorsement requests and responses, blocks from the orderer, and so on) are signed with the member’s private key. Because of this, other parties need a copy of the public key for the member in order to authenticate the originator of an operation and decrypt the message. Account A therefore needs a copy of the new member’s public certificates. Account A needs two certificates: the “admincert” to authenticate a user with a role of ADMIN, and the “cacert” to authenticate a user with a role of MEMBER.

Step 7: Account A creates an MSP folder for the new account B member

Account A creates an MSP folder and stores the admincert and cacert belonging to the new member. This MSP is used to verify the identity of the new member on any operations signed by the new member.

Step 8: Account A creates a configtx.yaml file that includes the new account B member

A channel config file (configtx.yaml) contains channel definitions as profiles, and also details of the members that make up the Fabric network. At this stage, configtx.yaml contains only details of the single member created by the network creator, account A. The new member has to be added to the various sections in this file. The new member should also be added to the appropriate profile in the profiles section as each channel configuration is generated using a profile.

The readme file in step 8 in the Git repo provides a template and a working example of a configtx.yaml file that supports two members.

Step 9: Account A generates a channel configuration

This step generates a new channel configuration block that includes the new member belonging to account B. A configuration block is similar to the genesis block, defining the members and policies for a channel. In fact, you can consider a configuration block to be the genesis block plus the delta of configuration changes that have occurred since the channel was created.

Out of interest, ‘genesis block’ appears in two places in Fabric:

  1. The orderer is bootstrapped using a genesis block, which is used to create the orderer system channel. The genesis block is created using the command configtxgen -outputBlock. It’s passed to the orderer on startup, usually by using an ENV variable or parameter (named GenesisFile). Managed Blockchain handles this for you.
  2. Application channels are created using a channel configuration block. The first of these becomes the genesis block for the channel. This is created using the command configtxgen -outputCreateChannelTx.

To create a new channel configuration block, first fetch the latest configuration block from the channel. You then generate a new channel configuration that contains the new member, then compare the old and new configurations to generate a diff.

Generating a new channel configuration involves a number of steps, which are detailed in step 9 in the readme.

Step 10: Endorsing peers sign the new channel configuration

The diff must be signed by the existing network members. That is, the network members must endorse the changes to the channel configuration and approve the new member joining the channel. A channel configuration update is really just another transaction in Fabric, known as a configuration transaction. As such, it must be endorsed by network members in accordance with the modification policy for the channel. The default modification policy for the channel Application group is MAJORITY, which means a majority of members need to sign the channel configuration update.

Because our network currently contains only one member, the network creator, this step isn’t strictly required because only the network creator needs to sign the package. However, I’ve made it an explicit step, because you need it when your Fabric network grows to two or more members.

To allow admins belonging to different members to sign the channel configuration, you need to pass the channel configuration diff file to each member in the network. You pass it to each one by one and have them sign the channel configuration. Each member signature must be applied in turn so that you end up with a package that has the signatures of all endorsing members. Alternatively, you can send the channel config to all members simultaneously and wait to receive signed responses. However, then you have to extract the signatures from the individual responses and create a single package that contains the configuration update plus all the required signatures.

After you have a signed channel configuration, you can apply it to the channel.

Step 11: Account A updates the channel with the new configuration

In this step, you update the channel with the new channel configuration. Because the new channel configuration now includes details of the new member, this allows the new member to join the channel.

Step 12: Account A shares the genesis block for the channel with account B

Before the peer node in account B joins the channel, it must be able to connect to the ordering service managed by Managed Blockchain. It obtains the ordering service endpoint from the channel genesis block. The configuration for the channel genesis block is stored in the file mychannel.block. Here, mychannel refers to the channel name and might differ if you have changed the channel name. This configuration was created when account A first created the channel. Account A shares the file mychannel.block with account B.

Step 13: Account B starts its peer node and joins the channel

The next step is to join the peer node belonging to the new member to the channel. After the peer successfully joins the channel, it starts receiving blocks of transactions. It builds its own copy of the ledger, creating the blockchain and populating the world state key-value store.

Step 14: Account B installs chaincode

To confirm that the peer node in account B is receiving blocks on the channel, you install chaincode. You then run a query against the local ledger on the peer. After installing the chaincode, the peer node in account B can run queries against its own world state database.

Step 15: Account B queries the chaincode

In this step, you run a query to confirm that the peer node is now maintaining its own ledger.

Step 16: Account B invokes a transaction

You might be surprised to discover that your peer node can run queries against its world state database but is unable to successfully invoke transactions.

Your account B peer node is now a committing peer. This means that the peer can validate the blocks it receives from the ordering service and maintain its own ledger. However, it is not yet an endorsing peer and can’t take part in endorsing transactions. In Step 16, you explicitly send the transaction to the account B peer node for endorsement. The peer in account B endorses the transaction and digitally signs it. However, the transaction fails the Fabric validation step because it doesn’t meet the endorsement policy of the chaincode on this channel.

When the account B peer node receives the endorsement request, it follows the standard Fabric process of simulating the transaction and endorsing it. This process includes signing the endorsement with the identity of the account B member. The endorsed transaction is then sent to the ordering service, which groups transactions into blocks and sends the blocks to the peer nodes. Each peer node then validates the transactions in the block. Transactions that fail the validation step are written to the blockchain on each peer as invalid transactions, and the world state isn’t updated.

The endorsement policy is usually specified when the chaincode is instantiated on a channel. If you look back at part 1, you see that you didn’t provide an endorsement policy during instantiation, so Fabric applies a default endorsement policy. In this case, it’s `“OR(‘Org1.member’)”`, meaning that transactions can only be endorsed by the creator organization.

You can resolve the invalid transaction in two ways:

  1. Send the transaction proposal to peer nodes in account A and account B. Because account A is able to endorse transactions, the transaction proposal is signed by both a valid and an invalid endorser. In other words, it contains endorsements from peers in account A and account B. When the endorsement policy is checked during the validation step, it succeeds as the transaction has an endorsement from a member included in the policy.
  2. Add the new member to the endorsement policy. To do this, the chaincode on the channel needs to be updated with a new endorsement policy that includes the new member.

In the next step, you add the new member to the endorsement policy.

Step 17: Account A updates the endorsement policy for the chaincode on the channel

Endorsement policies are defined when chaincode is either instantiated or upgraded on a channel. In this case, you upgrade the chaincode on the Fabric channel. This requires us to increment the chaincode version and install a new version of the chaincode on the peer node in account A. The chaincode itself doesn’t change; only the version number and the endorsement policy applied to it on this channel change.

Upgrading chaincode is very similar to instantiating, and should take around 30 seconds to complete. During this process, Fabric creates a new Docker chaincode container, installs the chaincode, and calls the init function. Keep this in mind when you design your own chaincode. The init function is going to run each time the chaincode is upgraded, so don’t make the mistake you see in the fabric-samples where the state is initialized in the init function. This results in the current world state being reset to the values defined in the init function each time the chaincode is upgraded. That is, you can erase your current world state and overwrite it with the default values specified in the init function. Best practice for Fabric is to have a separate function to initialize the state, and only call this once, during chaincode instantiation.

Step 18: Account B installs the latest version of the chaincode

The new version of the chaincode must now be installed on the peer node in account B. After the chaincode is installed, invoking a transaction and rerunning the query should confirm that the peer node in account B can now endorse transactions. The validation checks performed on each peer node confirm that a transaction endorsed by account B is valid, and the world state on each peer is updated. You can double-check this by first invoking transactions on peer nodes in account A or account B. You then run the same query on peer nodes in account A and account B. You should see the same results on both peers.

Conclusion

In this post, you added a new member owned by a different AWS account to the Fabric network you created in part 1. You then provisioned a peer node for the new member and added the new member to the channel configuration of an existing channel. Next, you joined the peer node owned by the new member to the channel. Finally, you updated the endorsement policy for the channel so that members in both the new AWS account and the original AWS account can endorse transactions on the channel.

Try Managed Blockchain by signing up for the preview.


About the Author

Michael Edge is a senior cloud architect with AWS Professional Services, specializing in blockchain, containers and microservices.