Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
Welcome, to part two of the âChoosing private blockchain techâ series (part1 is here). In each article we implement a simple use case to give an overview of what an existing technology does and how it can be useful in businesses.
Originally, this article was meant to be about Hyperledger Fabric, but after learning about Hyperledger Composer, it became clear that it would be beneficial to write about it first. This will allow us to get a higher-level view of what type of business applications can be built on top of Hyperledger Fabric blockchain and make it easier to understand the purpose of Fabric itself.
The business use case
Letâs start with the artificially simple use case from the finance industry defined in part1. Here are the parties in this scenario:
- Non-custodial asset manager (hedge fund): makes investment decisions (trades). Non-custodial means they donât actually hold a clientâs money. Instead, after a trade is executed they send directions to a custodian that moves the money appropriately.
- Custodian: Usually a large and trusted finance institution that holds a clientâs money and executes transfers on behalf of the hedge fund. A custodian needs to know about each trade to distribute payments to counterparties.
- Client(s): Invests into the hedge fund. Each client needs to view trades in their own account, but not other clientsâ accounts.
Letâs see how we can use Hyperledger Composer to define all participants in this scenario and enable them to share appropriate information.
What is Hyperledger Composer?
Hyperledger Composer is a higher-level toolset and framework made to quickly build and run applications on top of Hyperledger Fabric blockchain. If Fabric is network-level, Composer is application-level. It allows us to define the data model, business logic and access control lists for an application that can be deployed and executed inside of a Fabric channel. Users of such applications donât have to run a local node and can interact with a remote node through an RPC or HTTP REST if needed.
Composer comes with a nice web playground which allows users to prototype applications in browser without setting up a local network. Weâll use the playground to implement and test our use case. In a future article, we will export the resulting âbusiness network definitionâ and deploy to a real Hyperledger Fabric blockchain.
Solution
The full code of the solution can be found here. Bellow weâll see how to configure each piece step-by-step using the Composer Playground.
1. Create network
Select âDeploy a new business networkâ and fill out the required info. In my case, the name of the network is âhedge-fund-networkâ and admin card name is admin@hedge-fund-network. Select the âempty-business-networkâ template and hit Deploy. This will create an empty business network and an admin identity that has full control over it. After the business network is created we can connect to it by pressing âConnect Nowâ.
2. Configure object model
Composer has its own object modeling language that is very straightforward and easy to use. There are 4 types of resources that can be defined:
- Assets. Things that are being tracked in the application. In our case we track Lotsâââtraded blocks of securities.
- Participants. Entities that interact with the network. Each has their own permissions.
- Transactions are sent to update an asset or a participant as well as to execute a custom-defined logic.
- Events can be emitted from the transaction logic and subscribed to by participants.
Now, letâs create a model file named âorg.acme.mynetwork.ctoâ and add the following code. The file defines 3 participant types (Trader, Client, Custodian), Lot asset, Trade transaction and NewTrade event.
/** * My commodity trading network */namespace org.acme.mynetwork
asset Lot identified by lotId { o String lotId o String securityName o Double quantity o Double price --> Client owner}
participant Client identified by clientId { o String clientId o String description}
participant Custodian identified by custodianId { o String custodianId o String description}
participant Trader identified by traderId { o String traderId o String name}
transaction Trade { --> Trader trader --> Client client --> Lot lot}
event NewTradeEvent { --> Lot lot}
3. Configure transaction logic
Next, weâll implement a custom logic that gets executed every time a Trade transaction is sent. Create a new script file called script.js with the code below. Composer knows to execute this code for each Trade transaction based on the @param annotation in the comment. This code does 2 things: changes the owner of a Lot and emits a NewTrade event on success.
/*** Track the trade* @param {org.acme.mynetwork.Trade} trade â the trade to be processed* @transaction*/function tradeCommodity(trade) { var factory = getFactory(); trade.lot.owner = trade.client; var result = getAssetRegistry(âorg.acme.mynetwork.Lotâ) .then(function (assetRegistry) { return assetRegistry.update(trade.lot); }); if (result) { var newTradeEvent = factory.newEvent(âorg.acme.mynetworkâ, âNewTradeEventâ); newTradeEvent.lot = trade.lot; emit(newTradeEvent); } return result;}
4. Access control list (ACL)
Lastly, we need to define an access control list governing what each participant type can do and see. Here we specify that traders can execute trades, clients can view their own trades, and custodians can view all trades.
/* Admin */
rule NetworkAdminUser { description: "Grant business network administrators full access to user resources" participant: "org.hyperledger.composer.system.NetworkAdmin" operation: ALL resource: "**" action: ALLOW}
rule NetworkAdminSystem { description: "Grant business network administrators full access to system resources" participant: "org.hyperledger.composer.system.NetworkAdmin" operation: ALL resource: "org.hyperledger.composer.system.**" action: ALLOW}
/* Common */
rule CommonReadTransactionRegistry { description: "Allow all participants to read transaction registry" participant: "org.hyperledger.composer.system.Participant" operation: READ resource: "org.hyperledger.composer.system.TransactionRegistry" action: ALLOW}
rule CommonReadParticipantRegistry { description: "Allow all participants to read participant registry" participant: "org.hyperledger.composer.system.Participant" operation: READ resource: "org.hyperledger.composer.system.ParticipantRegistry" action: ALLOW}
rule CommonReadAssetRegistry { description: "Allow all participants to read asset registry" participant: "org.hyperledger.composer.system.Participant" operation: READ resource: "org.hyperledger.composer.system.AssetRegistry" action: ALLOW}
rule CommonReadNetwork { description: "Allow all participants to read network" participant: "org.hyperledger.composer.system.Participant" operation: READ resource: "org.hyperledger.composer.system.Network" action: ALLOW}
/* Trader */
rule TraderManageClient { description: "Allow traders to read all clients" participant: "org.acme.mynetwork.Trader" operation: ALL resource: "org.acme.mynetwork.Client" action: ALLOW}
rule TraderManageOwnTrades { description: "Allow traders to manage their trades" participant(t): "org.acme.mynetwork.Trader" operation: ALL resource(tt): "org.acme.mynetwork.Trade" condition: (tt.trader.getIdentifier() == t.getIdentifier()) action: ALLOW}
rule TraderManageLots { description: "Allow traders to read and create lots" participant: "org.acme.mynetwork.Trader" operation: READ, CREATE resource: "org.acme.mynetwork.Lot" action: ALLOW}
rule TraderUpdateLots { description: "Allow traders to update lots via Trade transaction" participant: "org.acme.mynetwork.Trader" operation: UPDATE resource: "org.acme.mynetwork.Lot" transaction: "org.acme.mynetwork.Trade" action: ALLOW}
rule TraderReadOwnTrader { description: "Allow traders to read their own info" participant(t): "org.acme.mynetwork.Trader" operation: READ resource(tt): "org.acme.mynetwork.Trader" condition: (tt.getIdentifier() == t.getIdentifier()) action: ALLOW }
rule TraderAddAsset { description: "Allow traders to add assets to registry" participant: "org.acme.mynetwork.Trader" operation: CREATE resource: "org.hyperledger.composer.system.AddAsset" action: ALLOW }
rule TraderCreateHistorianRecord { description: "Allow traders to create historian record" participant: "org.acme.mynetwork.Trader" operation: CREATE resource: "org.hyperledger.composer.system.HistorianRecord" action: ALLOW }
rule TraderReadOwnHistorianRecord { description: "Allow traders to read their own historian record" participant(t): "org.acme.mynetwork.Trader" operation: READ resource(hr): "org.hyperledger.composer.system.HistorianRecord" condition: (hr.transactionType == "org.acme.mynetwork.Trade" && hr.participantInvoking.getIdentifier() == t.getIdentifier()) action: ALLOW}
/* Client */
rule ClientReadOwnTrades { description: "Allow clients to view their trades" participant(c): "org.acme.mynetwork.Client" operation: READ resource(t): "org.acme.mynetwork.Trade" condition: (t.client.getIdentifier() == c.getIdentifier()) action: ALLOW}
rule ClientReadOwnEvents { description: "Allow clients to subscribe to NewTrade events" participant(c): "org.acme.mynetwork.Client" operation: READ resource(e): "org.acme.mynetwork.NewTradeEvent" condition: (e.lot.owner.getIdentifier() == c.getIdentifier()) action: ALLOW}
rule ClientReadOwnLots { description: "Allow clients to view lots they own" participant(c): "org.acme.mynetwork.Client" operation: READ resource(s): "org.acme.mynetwork.Lot" condition: (s.owner.getIdentifier() == c.getIdentifier()) action: ALLOW }
rule ClientReadOwnClient { description: "Allow clients to view their info" participant(c): "org.acme.mynetwork.Client" operation: READ resource(cc): "org.acme.mynetwork.Client" condition: (cc.getIdentifier() == c.getIdentifier()) action: ALLOW }
rule ClientReadTraders { description: "Allow clients to view traders" participant: "org.acme.mynetwork.Client" operation: READ resource: "org.acme.mynetwork.Trader" action: ALLOW}
rule ClientReadHistorianRecord { description: "Allow clients to view their historian records" participant(c): "org.acme.mynetwork.Client" operation: READ resource(hr): "org.hyperledger.composer.system.HistorianRecord" condition: (hr.transactionType == "org.acme.mynetwork.Trade" && hr.transactionInvoked.client.getIdentifier() == c.getIdentifier()) action: ALLOW}
/* Custodian */
rule CustodianReadAllTrades { description: "Allow custodian to view all trades" participant: "org.acme.mynetwork.Custodian" operation: READ resource: "org.acme.mynetwork.Trade" action: ALLOW}
rule CustodianReadAllLots { description: "Allow custodian to view all lots" participant: "org.acme.mynetwork.Custodian" operation: READ resource: "org.acme.mynetwork.Lot" action: ALLOW}
rule CustodianReadAllClients { description: "Allow custodian to view all clients" participant: "org.acme.mynetwork.Custodian" operation: READ resource: "org.acme.mynetwork.Client" action: ALLOW}
rule CustodianReadAllEvents { description: "Allow custodian to subscribe to NewTrade events" participant: "org.acme.mynetwork.Custodian" operation: READ resource: "org.acme.mynetwork.NewTradeEvent" action: ALLOW}
rule CustodianReadAllTraders { description: "Allow custodian to view all traders" participant: "org.acme.mynetwork.Custodian" operation: READ resource: "org.acme.mynetwork.Trader" action: ALLOW}
rule CustodianReadOwnCustodian { description: "Allow custodian to view their info" participant(c): "org.acme.mynetwork.Custodian" operation: READ resource(cc): "org.acme.mynetwork.Custodian" condition: (cc.getIdentifier() == c.getIdentifier()) action: ALLOW }
rule CustodianReadHistorianRecord { description: "Allow custodian to view all trade historian records" participant(t): "org.acme.mynetwork.Custodian" operation: READ resource(hr): "org.hyperledger.composer.system.HistorianRecord" condition: (hr.transactionType == "org.acme.mynetwork.Trade") action: ALLOW}
After all steps are completed, we can deploy the application by clicking Update on the left.
How to test in Playground
Now that we have the complete definition of our application, we can test it using the Composer Playground Test module (click Test at the top).
1. Create participants
First, letâs seed our application with some participants. We can create 2 clients: a custodian and a trader.
2. Create identities for each participant
In order to be able to interact with the business network a participant needs an associated identity. Identities can be created in the ID registry (open the user dropdown on the top right). Weâll create an identity for each participant by specifying its name and pointing to an instance of the participant created in the previous step. At a minimum, we need 4 identities: 2 clients, 1 trader, and 1 custodian.
We can now login using the newly created identities by clicking âUse nowâ next to each identity in the list. First, we login as a trader and create a new Lot that doesnât belong to any client (client ID is null).
Then, we assign the ownership of this lot to client 1 via a Trade transaction.
Now, letâs create one more lot and assign it to client 2 via another Trade.
Then, weâll login as client 1 and client 2 to check if we can see our Lots.
As you can see, each client sees only lots that they have ownership of and they are not aware of trades for other clients.
5. Login as Custodian
Letâs login as a custodian to check that we can view all trades. Indeed, both trades are visible, as you can see below.
Custodian can also view history of all trades:
Note on decentralization
Keep in mind that when a transaction is broadcasted to the Hyperledger Fabric network, each configured peer is independently executing the custom transaction processing logic which ensures the correctness of the blockchain update. Thatâs a major architectural difference andâââin many casesâââan advantage over the traditional centralized, client-server approach. In the traditional approach a single organization would be responsible for managing the data and exposing it to other participants, forcing others to trust it and making it a potential single point of failure.
In the blockchain approach, each peer is responsible for managing and reconciling their own copy of the data. This makes the entire network more resilient and decentralized. However, it is not completely simple to configure. There are additional privacy implications to consider since the data is now hosted in many places which creates a potentially larger threat surface.
Conclusion
Hopefully this has given you a better understanding of what Hyperledger Composer is and how it can be useful in sharing information and keeping track of assets and other concepts among multiple participants. Feel free to export the .bna file of your network and follow the tutorial here to deploy the application to a local Hyperledger Fabric network. Weâd love to hear your thoughts on Hyperledger Composer. Please, leave any questions or comments below.
Choosing private blockchain tech: Hyperledger Composer was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.