Finally, Fix my Bike with Hyperledger Fabric (Deploy Daml application on a Fabric Network)
We continue our demonstration of Daml working with various types of ledger. In the previous several articles, we have walked through the code and tested it with Daml Studio (link), and then the same code on Daml Sandbox and Navigator (link). The latest one is the same code persistent in PostgreSQL-based ledger (link), which is close to a production environment when a centralized ledger is required. In case a distributed or decentralized setup is needed, like a cross-organization deployment, we can use a distributed ledger environment. In this article we use the same “fix my bike” example and deploy it over a fabric-based Daml ledger. You will see all happening at the backend side, and it does not present any difference when using this Daml application.
Besides, I also include some observation from Fabric network side and see how daml-on-fabric is working with a fabric network.
It is obvious that this setup is composed of two systems developed separately: Daml application and Hyperledger Fabric (Fabric). Those reading this series of articles should know Daml well. Here is just a quick overview on some concepts in Fabric, which will be referred to later in this article.
Quick Overview of Hyperledger Fabric
Hyperledger Fabric is an enterprise blockchain platform for building consortium applications. The consortium application is serving multiple organizations, such that all of them are accessing the same source of trustful information (from the ledger), and executing the same business logic (chaincode).
A typical fabric network is composed of two types of nodes: peer and orderer. Peers keep ledger, responsible for committing new blocks, updating world state, and executing chaincode when needed. Orderers are responsible for new block creations. In a typical setup, peers are deployed in participating organizations, while orderers usually run as a cluster in a separate organization. This is the setup of our demonstration.
Note: in a decentralized setup, orderers are running in each participating organization. Both centralized and decentralized ordering services are supported in Fabric. For those who are interested in this decentralized setup, please refer to these two articles (link and link).
Channel is a key aspect in Fabric, representing a group of organizations sharing the same ledger and deployed with the same set of chaincode. A fabric network supports more than one channel, and an organization can join one or more channels.
Each peer holds a ledger per channel. Ledger is composed of two parts: blockchain keeps all the transactions in a “blockchain” structure, while the world state database stores the latest states. When a new block sent by an orderer is received by peer, the peer will commit the block: if all transactions are validated, the block is appended on existing blockchain, and the world state is updated.
As a permissioned blockchain platform, every component in the network (orderer and peer) and every user using the network are identified and authorized. This part is implemented by Member Service Provider (MSP), which is done through Certificate Authority.
These are the concepts we will see in our demo. For detail please refer to the Fabric documentation (link).
Fabric Network in this Demo
Our demonstration is a simple two-peer-org setup, with a separate orderer organization. One peer exists in each peer organization, while one orderer is in orderer organization. A channel mainchannel is created and joined by both peers. After that network is up and running, a chaincode daml_on_fabric is deployed in mainchannel. It contains those functions to be invoked later by the daml-on-fabric driver (seen below).
Here is how the fabric network looks.
Daml-on-fabric is the software enabling Daml application running on top of Hyperledger Fabric. In short, on one side daml-on-fabric presents a standard Daml ledger API to Daml application, while on the other side invokes chaincode functions in the fabric network where the ledger is kept.
Daml-on-fabric can be roughly divided into two parts.
The part deployed in the fabric network is the chaincode, in which the data structure to be stored in the ledger and the functions acting upon the ledger are defined. The design of chaincode is closely coupled to how Daml ledger is operating, and the functions will be invoked by the client application. The chaincode is written in Golang and here you can find the chaincode (link).
The other part is the daml-on-fabric driver (driver). It presents the Daml ledger API to the Daml application. When Daml runtime needs to change contract state (e.g. create a new contract), the driver is responsible for invoking chaincode functions to update the state. From fabric perspective, this is the client application, with proper authorization to perform these tasks. The daml-on-fabric driver is written in Scala.
When we run the daml-on-fabric, we specify the DAR files created through compilation of our model (Daml code). It will be shown in the demonstration later.
The daml-on-fabric repository provides the driver, plus all the necessary components for setting things up. The driver comes with the sample fabric network setup mentioned above. All crypto material, MSP definition and network components are there. A script
fabric.sh is prepared for bringing up and tearing down the network, which is also used by another script
The daml-on-fabric driver is brought up through the scala build tool (
sbt). The driver will first create an application channel for the driver (mainchannel) and then install and commit the chaincode (daml_on_fabric) to the channel. After working on the fabric network, the driver is being brought up and gets the Daml ledger API ready for Daml runtime.
There are several options in daml-on-fabric. You can refer here for more details.
Our demonstration uses the daml-on-fabric repository to bring up the setup. Like previous articles, we again apply the “fix my bike” model. After the setup completes, Navigator is brought up and we repeat what we have done in previous articles.
Here is the setup for demonstration.
Step 1: Bring up the fabric network
First we clone the daml-on-fabric repository.
git clone https://github.com/digital-asset/daml-on-fabric.git
As mentioned, this repo has all on the daml-on-fabirc driver, and a pre-configured fabric network. Bring up the fabric network first.
With this we have a fabric network, with an orderer org and two peer org (org1 and org2). Note that no channel is created yet. The channel and chaincode will be established by daml-on-fabric driver later. Keep this terminal as it shows all logs from the fabric network perspective.
When we open another terminal, we see those network components running
And no channel is yet configured in the peers.
Ignore the directory
~/my-proj, as this docker command can be issued anywhere. We will create
damlcommand in the next step.
Step 2: Compile Daml code
We follow the same set of Daml code for our “fix my bike” model. Here we repeat the process and prepare two files for this model.
daml new my-proj --template skeleton
module BikeShop wheredata Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)template Cash
controller owner can
Transfer : ContractId Cash
create this with owner=newOwnertemplate BikeRepair
signatory bikeShop, bikeOwner
controller bikeOwner can
Pay : ContractId Cash
cashCid: ContractId Cash
cash <- fetch cashCid
cash.currency == CHF &&
cash.amount == price)
exercise cashCid Transfer with newOwner=bikeShoptemplate BikeRepairProposal
controller receiver can
Accept : ContractId BikeRepair
With this we can build the DAR file. This will be used later for deployment.
Step 3: Bring up daml-on-fabric
The following is the command to bring up the daml-on-fabric with our project.
sbt "run --port 6865 --role provision,time,ledger ../my-proj/.daml/dist/my-proj-0.0.1.dar"
Effectively, this command performs
- create mainchannel
- deploy daml_on_fabric chaincode
- deploy our daml project by invoking chaincode functions
- provide the ledger access point localhost:6865
Step 4: Inspection from Fabric Perspective
We first take a look on the channel in both peers. Both joined mainchannel.
Then we take a look on the ledger in both peers. The ledger is identical in both peers (see the height and the block hash). This means the fabric network is working well.
Finally we observe the world state database, through couchdb. As ledgers are identical on both peers, here we only inspect the world state database from peer0.org1.
Note: Here I modify the
docker-compose.yamlfile to include two couchdb, one for each peer, and let the peers use the couchdb as the world state database. This is for observation only. You can refer here for more information about using couchdb in Fabric.
And inside which there are quite many records. These are where the Daml ledger is kept.
The detail design on the ledger is out of our scope. They are categorized as following.
- Record Time
Step 5: Allocation Parties to Ledger
Unlike PostgreSQL, the daml-on-fabric does not allocate parties. For demonstration purposes we allocate Martin, BikeShop and SwissBank into our setup. This is to align with the Navigator (in the next step) when it reads from
daml ledger allocate-parties --host localhost --port 6865 Martin BikeShop SwissBank
We notice that new transactions are invoked to record the parties in the ledger. If we do a quick check on the blockchain height, it is 31 now, 3 more than the previous check (see Step 4). We can assume that each allocation is a transaction being invoked on the chaincode.
Step 6: Run Navigator
Now launch Navigator to perform our demonstration on Daml ledger. Note that the roles available in Navigator are obtained from
daml.yaml, not from the ledger.
daml navigator server --port 7500
As previous articles, we perform the following tasks of creation of contract and exercising of choices.
- SwissBank created Cash for Martin
- BikeShop proposed Martin for the service
- Martin accepted the proposal
- Martin paid according to the repair contract
Here we only show the results after the tasks. The results are identical to our previous articles.
And finally we can see each choice is a transaction invoked in the chaincode. The latest blockchain height is 35, 4 blocks (i.e. 4 transactions) are created during our scenario.
This ends our demonstration.
One of the advantages of Daml is that the smart contract code is written once and can be deployed in a variety of environments, depending on the business requirement. So far we tested PostgreSQL in a previous article, and in this we tested Fabric.
From Daml perspective, the runtime is speaking to the ledger through the Ledger API interface. Therefore the driver plays a role in making the underlying environment Daml-ready. While PostgreSQL looks quite simple, it is not that straight forward in Fabric.
Fabric itself is a mature platform including its own software components and all the game rules. Just consider that the Fabric itself is an environment where one can build its own smart contract and application on top of it.
The design of daml-on-fabric is to make fabric network more like a distributed database. To make this happen, we still use a fabric network with peers and orderers running. Fabric ledger is still kept in peers. A tailor-made chaincode is needed, presenting chaincode functions that are just sufficient for the daml-on-fabric driver. With this chaincode deployed, this fabric network becomes a distributed database, through the daml-on-fabric driver.
As a result, certain native features in fabric are no longer accessible, or at least no necessary. For example, private data in Fabric provides data privacy between organizations, which is not used in daml-on-fabric. Of course it is now handled by Daml runtime. And there is no association between parties in Daml world and users / organizations in Fabric world. Different parties interacting with Daml applications are seen as transactions from a single user in Fabric. While it may be technically feasible to implement parties in Daml to users in Fabric, it is not implemented in daml-on-fabric currently.
Of course, the daml-on-fabric only consumes one channel. A fabric network supports multiple channels for different applications, and daml-on-fabric is just one of them. Those requiring other native fabric features can work directly on their own chaincode in a different channel.
In this article we have demonstrated how to use daml-on-fabric to deploy a Daml model over a fabric network. Hope this provides a more complete picture of how flexible Daml is, when choosing ledger deployment: from a centralized database like PostgreSQL to a distributed ledger technology like Fabric.