Building a Private Ethereum Consortium
The travel industry estimates 3-5% of bookings are disputed due to discrepancies in the data held by each party and can take months to resolve. Over the past two years, Microsoft and Webjet have collaborated to build a blockchain-based solution, Rezchain, that helps travel companies resolve data and avoid invoice reconciliation issues. You can read more about our previous work in the following code stories: Using a Layer 7 proxy for Ethereum Blockchain, Using Helm to Deploy Blockchain to Kubernetes.
Earlier this year, Webjet announced the expansion of Rezchain. One of the challenges we faced in our recent hackfest with Webjet was how to connect each party’s Ethereum network to form a consortium. For a consortium, Ethereum nodes should be distributed across the network and, optionally, each participating member of Rezchain will host their own Ethereum nodes. In this code story, we’ll share some of the lessons we learned in creating the Rezchain consortium. In particular, we’ll focus on how we solved the challenges involved with enabling Ethereum nodes to peer inside and across virtual networks.
In this article by Vitalik Buterin, co-founder of Ethereum, blockchain applications generally fall into three categories based on their access privileges and who can participate in the consensus process: public, consortium, and private.
In a public blockchain, anyone can read and send transactions to the chain and participate in the consensus process. On the other hand, with a private blockchain write permissions are centralized to a single organization and read permissions can be restricted to an arbitrary extent. Falling in the middle of the spectrum, a consortium blockchain has read and write permissions limited to a certain number of parties in the network.
It is important that hotel booking transactions and any company-sensitive data remain private. Any data on the blockchain would be disclosed to all connected parties, and Webjet decided to store hash values to ensure sensitive details are not stored on the chain. As the blockchain eco-system is still evolving, Webjet has decided to run blockchain as consortium model at the moment. It also helps with efforts to maintain and support blockchain transaction nodes and miners. The Rezchain’s consortium consists of Webjet subsidiary hotel distribution brands, such as Lots of Hotels and JacTravel, with each company controlling and hosting their own Ethereum nodes. The challenge is how to enable the Ethereum nodes from one network (Lots of Hotel) to connect and peer with Ethereum nodes of another (JacTravel) where these Ethereum nodes could be potentially located in various parts of the world and hosted under different network topologies and network constraints. Working in collaboration with Webjet, we arrived at a solution that will enable Ethereum nodes to connect over the public Internet and to form a blockchain consortium.
Before presenting the final solution, background information of the methods that Ethereum employs to discover and peer with other Ethereum nodes is necessary.
There are 3 different ways in which peers can be configured: bootnode, static nodes, and trusted nodes:
|Uses Node Discovery
|Transport Protocols Used
|Adheres to Max Peers
Bootnode is a lightweight application used for the Node Discovery Protocol. Bootnodes do not sync chain data. Using a UDP-based Kademlia-like RPC protocol, Ethereum will connect and interrogate these bootnodes for the location of potential peers. The Ethereum Foundation maintains several bootnodes for the public Ethereum networks; the endpoints of which are hard-coded in the Geth source code. The default list can be configured using the
geth --bootnodes [enode://pubkey1@ip1:port1,enode://pubkey2@ip2:port2,…]
Given the list of potential peers, Geth will then attempt to connect to each peer over TCP to negotiate and ensure compatibility with protocol version, network IDs, and genesis blocks.
$ admin.addPeer("enode://email@example.com:30303") $ admin.addPeer("enode://pubkey@ip:port")
Or by supplying a “static-nodes.json” file in the Geth data directory:
$ cat GETH-DATA-DIR/static-nodes.json [ "enode://firstname.lastname@example.org:30303", "enode://pubkey@ip:port" ]
Similar to Static Nodes, Trusted Nodes are pre-configured peers which Geth will always try to stay connected to even after the peer limit has been reached. The peer limit is a limit to the number of peers that a Geth node can connect to; the default value is 25, but it can be configured using the
--maxpeers flag. Trusted Nodes can be configured by supplying a “trusted-nodes.json” file in the Geth data directory:
$ cat GETH-DATA-DIR/trusted-nodes.json [ "enode://email@example.com:30303", "enode://pubkey@ip:port" ]
Connecting the Consortium
In this section, we’ll present a generalized approach to connect the Ethereum nodes of each member to participate in the consensus process and form a consortium.
Using Helm to Deploy Blockchain to Kubernetes walks through deploying an Ethereum network to Kubernetes using Helm. In doing so, you will have an Ethereum network that looks like the following:
In order to connect the Ethereum networks of each member, we applied a mixture of Ethereum’s peering strategies to enable the Ethereum nodes of one member’s network to peer and communicate with nodes from another network to form a consortium.
As shown in the diagram above, building upon the original Helm chart, we made a couple of modifications to enable peering across virtual networks.
Within a member’s network, we used bootnode for discovery and peering of Ethereum nodes. In doing so, this enables easier scaling in/out of Ethereum nodes as each new node will be able to discover other peers using the Ethereum Node Discovery Protocol. For high availability, we deployed several replicas of bootnode. On start-up, each bootnode registers against a registrar (bootnode-registrar) that maintains a list of active bootnodes. Prior to an Ethereum node launching, an HTTP call is made to the bootnode-registrar service to retrieve the list of bootnodes and then passing the list of bootnodes to the Ethereum node using the
--bootnodes flag. The bootnode-registrar is available on GitHub and an accompanying Helm chart can be used to deploy the networks for one of the consortium members.
To connect a member’s Ethereum network to another member, we exposed the P2P ports of one Ethereum node (Geth-Tx-Public) to the public internet. Following the same pattern as the bootnode-registrar, the public Ethereum node registers with a registrar (staticnode-registrar) and subsequently retrieves a list of nodes that have registered. The list is then passed to Geth through the static-nodes.json configuration. The staticnode-registrar is available on GitHub (note: the repository is named ‘bootnode-registrar’).
Once the discovery and peering is complete, the Ethereum network will look like the following diagram:
As companies begin to explore scenarios to leverage blockchain, consortium blockchains are becoming increasingly popular. This code story has walked through the learnings of our collaboration with Webjet in building a blockchain consortium. One of the biggest challenges we faced in our engagement was how to enable Ethereum nodes to be able to discover and peer with one another – an obstacle we overcame using a mixture of Ethereum peering techniques and custom services (bootnode-registrar and staticnode-registrar).
In order to deploy our network in a more highly available nature, we’ve developed registrars for the bootnode and staticnodes which we have made available on GitHub. Please note that the implementation of the registrars is incomplete and does not offer any level of security. If you have any questions or feedback on this code story, please reach out in the comments below or through the respective GitHub repositories.
- News Article: Webjet launches blockchain-as-a-service hotel distribution solution
- Using Helm to Deploy Blockchain to Kubernetes
- GitHub: Helm Chart to Deploy a Private Ethereum Network
- GitHub: Bootnode-Registrar
- GitHub: StaticNode-Registrar (Note: the repo is named ‘bootnode-registrar’)