How much is the fish?

16
Sep

Let’s Blockchain with Hyperledger Fabric and Composer

Few technologies have made such a strong impression in regards to their implementation as Blockchain. The image of blocks lined up as a chain is literally embossed in people’s minds. Many conversations about Blockchain revolve around this image and the actual implementation. That's all nice and fun, but it also carries the risk that the key issue is passed over in the discussion: the application. Therefore, the goal of this article is to explore that issue above all. We need to clarify when and why a blockchain solution makes sense. Then, using Hyperledger Fabric and Hyperledger Composer, we will also implement a small use case directly.

The world’s largest container shipping company Maersk has launched the TradeLens [1] platform in cooperation with IBM. TradeLens now has more than ninety partners who really just want to do one thing: transfer goods digitally via TradeLens. So this can for example be a salmon caught in the northwestern Pacific, which finds its way to our German retailers through a number of stations. TradeLens is based on Hyperledger Fabric. But what is Hyperledger Fabric and why can such technology be interesting for trading platforms like TradeLens?

Hyperledger Fabric is a framework that was explicitly created for the development of business applications on distributed ledger technologies (DLT). Four points are essential here, which differentiate Hyperledger Fabric from public solutions such as Ethereum or Bitcoin: Anonymous participation in the network is not possible. Each participant has an identity for authentication and corresponding roles for access control. Confidential transactions can then be used to control who is allowed to see and execute them. In addition, no proof-of-work validation is necessary; it would not be practical for a business application anyway, since the consensus mechanisms would take too much resources and time. In Hyperledger Fabric, validation and consensus building are depicted through the distributed validation of transactions, resulting in the fourth property: the ability to implement business logic.

Hyperledger Fabric in the Hyperledger Universe

Hyperledger is a Blockchain open-source project which was launched in 2015 under the auspices of the Linux Foundation. The term Hyperledger does not refer to a specific technology here, but rather a project in which several teams develop DLT frameworks and tools. The goals are reusability, standardized interfaces and interoperability between the different projects. Listed below are the five currently active Hyperledger DLT frameworks and their main drivers:

 

  • Hyperledger Sawtooth (Intel)
  • Hyperledger Iroha (Suramitsu)
  • Hyperledger Fabric (IBM, Digital Asset)
  • Hyperledger Burrow (Monax)
  • Hyperledger Indy (Sovrin)

 

For tools, there are also five currently active projects with differing goals:

 

  • Hyperledger Caliper (Blockchain benchmarks)
  • Hyperledger Cello (Creation and management of Blockchain infrastructures)
  • Hyperledger Composer (Development of business network applications based on the Composer high-level language)
  • Hyperledger Explorer (Visualization of operational Blockchain systems)
  • Hyperledger Quilt (interoperability between different Blockchains)

 

We will now use Hyperledger Fabric as a DLT framework and Hyperledger Composer as a tool.

Asset Tracking – Same status for everyone

Going back to our trading platform example- we still need to answer the question of where the fish which we buy in the retail sector comes from. But also, which way did the fish take to get there? And how often, for example, did duties have to be paid or freight papers have to be exchanged? Digital information processing at the level of a single trader is usually quite good. However, each of these individual traders maintain well-kept information silos. Exchange of data or even a common database is usually dead loss in these cases. Yet that’s exactly what global trade could benefit from. In a system where all participants process the same data, trading can be made more efficient, safer and, above all, more traceable. But who should have sovereign rights to the data? Everybody on equal terms would be best – and that’s what distributed ledger technologies like Hyperledger Fabric offer.

The ledger is a data management system that keeps track of transactions and the resulting status of goods. In the Hyperledger context, these goods are called Assets. The transactions are carried out by Participants. So let’s move on with our fish: the frozen salmon we have acquired is an asset. It is transferred from the catch all the way to our supermarket through many participants. Each participant transfers the asset, changing its status and owner in the process. Each fish has exactly one single status in a data management system. This information is traceable for all participants and above all, it is stored in the Ledger with no possibility of alteration.

Hyperledger Composer – focus on the essentials

So how are assets and participants modeled and implemented in Hyperledger Fabric? Natively you can do that in Go, JavaScript or even Java. However, the initial hurdle is quite high and you end up with a large amount of boilerplate code. That’s why Hyperledger Composer as a tool was launched. It allows you to develop Hyperledger Fabric applications, while hiding the complexity of the underlying infrastructure. Assets and participants are defined using the internal object-oriented Composer Modeling Language.

So what would our fish look like as an asset? To keep our example as simple as possible, let’s assume that a fish has the properties of ID, species, weight, catch date and owner (Listing 1).

Listing 1
asset Fish identified by id {
  o String id regex=/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/
  o String type
  o Double weight
  o DateTime caught
  --> Retailer owner
}

The code is self-explanatory and already illustrates one of strengths of Composer: simplicity. But definitely more complex domains and problems can be modeled. Concepts such as namespaces, imports, abstract types, enums, relationships, validations, optional fields and default values are available for this. In Fish, you see a regular expression that checks the ID for a UUID format. The owner – Owner – is represented by a relationship.
The participants are similarly defined using the keyword Participant. In our use case, all participants are any form of a trader. Therefore it makes sense to define an abstract Retailer (Listing 2).

 

Listing 2
abstract participant Retailer identified by id {
  o String id
  o String name
  o String country optional
}

Specific assets, such as a shipping company, the vessels of which initially catch the fish, can then be derived from this and extended (Listing 3).

Listing 3
participant ShippingCompany extends Retailer {
  o Ship[] ships 
}

Since a ship is neither a participant nor an asset and serves only as a structuring aid, it can be modeled as a so-called concept (Listing 4).

Listing 4
concept Ship {
  o String name
  o Integer brt 
}

We now model a logistics company as yet another participant, which buys the caught fish from the shipping company and distributes it further (Listing 5).

Listing 5
participant LogisticsCompany extends Retailer {
  o Truck[] trucks 
}

Distributed transactions for consensus

“I can also map assets and participants using my own database, why all the work?” is the question many will ask themselves now. We can certainly reproduce this in a centralized system. But we have to keep in mind what participants the system has: if a consortium of trading partners – as was done in TradeLens for example – decide to implement a trading platform, who should have sovereign rights over the data? With Hyperledger Fabric, each participant keeps the data – asset status and transaction logs – and everyone is equally involved in the system. This not only avoids making decisions about data sovereignty, it also eliminates the need to have to pay a central instance for the operation of a database.
Moreover, we need more than just pure data storage. Real added value is only achieved when we implement transactions. So back to our fish: along with the trade, payments must be made. Prices vary, for example depending on the quantity purchased, on the quality or even the time of day. These conditions become the logic of a transaction. Together, assets, participants and transactions form the Chain Code. Other DLT frameworks also refer to this as Smart Contracts. Transactions are modeled just like participants and assets (Listing 6).

Listing 6

transaction TransferFish {

  o String contractId

  --> Retailer newOwner

  --> Fish fish

}

The simple transaction shown in Listing 6 describes a change of ownership of a fish. There is an ID for the contract resulting from this transaction, a new owner, and of course the fish asset involved. We have not yet modeled a contract asset. For the implementation of the transaction, we assume that a Contract has been modeled, which has a price, an old owner and new owner, as well as the reference to the fish and of course an ID.

 

Listing 7

/**

 * @param {de.example.TransferFish} tx 

 * @transaction

 */

async function transferFish(tx) {

    // Calculate price

    let price = calculatePriceFor(tx.fish)

    if (tx.fish.weight > 10000) {

      price *= 1.2

    }

    // Create a contract

    const contract = getFactory().newResource(assetNamespace, 'Contract', tx.contractId)

    contract.newOwner = getFactory().newRelationship(participantNamespace, 'LogisticsCompany', tx.newOwner.getIdentifier())

    contract.oldOwner = getFactory().newRelationship(participantNamespace, 'ShippingCompany', tx.fish.owner.getIdentifier())

    contract.fish = getFactory().newRelationship(assetNamespace, Fish, tx.fish.getIdentifier())

    contract.price = price




    // Persist contract

    const contractRegistry = await getAssetRegistry(`${assetNamespace}.Contract`)

    await contractRegistry.add(contract)




    // Change ownership of the fish

    const fishRegistry = await getAssetRegistry(`${assetNamespace}.Fish`)

    let fish = await fishRegistry.get(tx.fish.getIdentifier())

    fish.owner = getFactory().newRelationship(participantNamespace, 'LogisticsCompany', tx.fish.owner.getIdentifier())

    await fishRegistry.update(tx.fish)

}


 

The function (Listing 7) is pure JavaScript with the support of Composer SDK. The comment to the function specifies that this is a transaction and in the transaction object we have transfer Fish. Each fish is sold at a special price. In the transaction, this calculation is outsourced to a dedicated specialist function which can be arbitrarily complex. For example, you could model a demand asset such that the transfer will only be accepted by the potential buyer at a certain price. In the presented transaction, there are only two prices, the standard price and one with a twenty-percent markup for very large fish. The contract asset is only there to record the terms and conditions of a conducted transaction. Finally, the receiver becomes the new owner of the fish and the corresponding asset will be updated.

How can other participants be sure then that buyers and sellers did not cheat? You just simply carry out the transaction as well and compare its result with the one received. In the above example, we would check if the correct price was saved and if the new owner is actually also the receiver of the transaction. This process is called endorsement. A transaction is not considered valid until a sufficient number of participants have “endorsed” it. The Endorsement Policy of the network defines how much exactly the sufficient number of endorsements is. But it should be bigger than one. This is the only way to ensure that at least one other participant has also checked the transaction.

A multi-level process will run through until a transaction can be considered as valid by all the participants. To make sure we can understand how this important step of the endorsement takes place, let’s look at an example:

Fig. 1: Schematic presentation of a Hyperledger Fabric network

Figure 1 shows a Hyperledger Fabric network with three participants: Fischer AG, Middle-Man GmbH and Auditor. Each of these participants operates nodes, which are divided into the three categories: Peer, Client and Orderer. A Client is the interface to the network and the starting point for new transactions. Peers store the asset state and the transaction history in their own ledger. In addition, peers may have the special Endorser role, meaning they are considered for necessary endorsements. The Orderer determines the sequence of valid transactions and distributes them to the Peers of the network. The Orderer is presented as a bit of an oddball here. In the current version of Hyperledger Fabric, there are two ways to implement an Orderer: Solo or Kafka. Even if Kafka is distributed, it is a centralized service used by our Hyperledger Fabric network. Consensus in the network is achieved through the complete regulation of the transactions by the Orderer. Further implementations of the Orderer concept are planned in later releases of Hyperledger Fabric, which should make it possible to distribute it to the infrastructure of the individual participants as well.

The initiation of a transaction is also illustrated in Figure 1. For the endorsement of a new transaction, a client sends a so-called Propose message (1) to the endorsement peers. That way the client asks the endorsers to simulate and validate the transaction. Nothing has been written to the ledger yet. If successful, the endorser will sign the response and send it back to the client. (2) The Endorsement Policy determines how many endorsers must have at least simulated the transaction. If the client then receives a sufficient number of positive responses, the transaction is distributed through the orderer to the peers so that they can now update their ledger according to the transaction. The endorsement policy is therefore a very central element of the system. By having different peers simulate and validate the same transaction, trustworthiness is built – and that’s exactly what we want to achieve.

But how do we integrate ourselves into the existing world? The chain code given above is completely isolated, but sometimes it may be useful to use external services as well. So let’s assume that the fish should be traded at current market prices. That means that we have to source the current fish price from an external source.

Listing 8

async function transferFish(tx) {

  let price = await request.get(‘https://currentprice.com/fish’)

  if (tx.fish.weight > 10000) {

    price *= 1.2

  }

  ...

}

In Listing 8, an external service is used to determine the current fish price. Now let’s recall what happens when a transaction is executed – here we will probably quickly realize that this can be a dangerous idea in the end: due to the required endorsement, the transaction will be validated by n peers. That also means that n peers will call up the external interface. Let’s suppose that the base price of the fish changes during the endorsement. So we can have a situation in which endorsers receive different results; therefore a consensus cannot be reached as to the result. So the transaction would not be validated in this case. We should only use external services if:

 

  1. they do not change and use any states,
  2. they are idempotent, meaning that they always generate the same outputs for the same inputs.

 

In general, the chain code has to be deterministic. For example, you should absolutely avoid having a UUID or timestamp generated and committed within a transaction. Since the results would be different for each endorsement, no consensus would be found. The transaction would therefore never be executed.

Restrictions during execution

The question of who can sell the fish, or who can execute the translation, still remains open. So far, the transfer fish function does not include a permission check. This means that currently any participant – regardless of the actual owner – could transfer any fish asset. In general, we have two ways to implement permission checks. For one thing, we could check in the transaction whether the current owner of the fish asset also triggered the transaction.

 

Listing 9

async function transferFish(tx) {

  if (tx.fish.owner.getFullyQualifiedIdentifier() !== getCurrentParticipant().getFullyQualifiedIdentifier()) {

    throw new Error(‘Attempted to transfer fish that is not owned by the sender.’)

  }

  ...

}

Implementation in code (Listing 9) is perhaps the most obvious approach, but here the actual business logic is heavily mixed with the permissions, leading to unnecessary complexity. Composer therefore offers its own declarative Access Control Language (ACL) – the ability to implement access permissions detached from the actual business logic. The ACL distinguishes between access to the business network such as assets, participants and transactions as well as administrative access as a network admin. In both cases, the least privilege principle applies, which means that we must allow access explicitly. The permissions are defined in the permissions.acl file. If the file is not present, everything is allowed. We will create the entry shown in Listing 10 there.

Listing 10

rule TransferFishOnlyThroughOwner {

  description: “Only the owner of a fish asset is allowed to transfer it."

  participant(t): “de.example.Retailer"

  operation: UPDATE

  resource(c): "de.example.Fish"

  transaction: "de.example.TransferFish"

  condition: (c.owner.getIdentifier() === t.getIdentifier())

  action: ALLOW

}

With this entry, we make sure that the UPDATE operation on the asset Fish may be executed only by the owner of the asset through the TransferFish transaction. We check the condition for access here based on the participant who executed the transaction. Such a condition could for example also be a simple validation of transaction data. So we have the ability to centrally specify access permissions. However, it has been shown that this can quickly become very confusing and therefore the ACL is subject to constant refactoring and should be sufficiently tested.

Added value through queries

In principle, we now have the most important Composer Tool ready. We have seen how assets, participants and transactions are implemented and used. So we know how to describe a fish and its traders using Hyperledger Composer and send it on its digital way. In addition, by describing the endorsement, we have seen how Hyperledger Fabric brings trustworthiness to transactions for a consortium of traders. Another important point that we have not yet considered is reading of the data. Data storage in the ledger takes place in a CouchDB. This allows complex queries using an SQL-like syntax. For example, each trader could use such queries to find out which contracts the trader had completed to date. You can describe these queries using so-called Querys (Listing 11).

Listing 11

query ContractsForParticipant {

  description: "Returns all contracts for a participant"

  statement: 

    SELECT  de.example.Contract

    WHERE   (

      (oldOwner.id == _$participantId) OR

      (newOwner.id  == _$participantId))

}

Queries have pure read access. Unlike for transactions, no endorsement is necessary and the queries can be made on the local ledger.

Permissioned Ledger

Can anyone simply join in? No. Hyperledger Fabric implements a so-called Permissioned Blockchain. This means that all participants are known. Therefore, a consortium is a very central element in this context. Traders need to come together to form a consortium (like was done at TradeLens) and jointly implement the platform. From a technological viewpoint, this closed pool of candidates has the great advantage of being able to do without strict and complex consensus algorithms such as proof of work, letting you achieve significantly higher throughput.

But if we assume that we have a closed pool of known participants, there is still the issue of how each participant can be assigned a digital equivalent. The relation between physical and virtual participants is created using Hyperledger Composer through the generation of so-called Identities. This assignment results in the creation of a so-called card. This contains the connection information to the network as well as an X.509 certificate required for authentication. Let’s take a quick look at one of the traders (Fischer AG) in the consortium and how this trader can now participate in the network:

The participant Fischer AG is provided with the fischer_ag.card over a secure communication channel. If Fischer AG wants to transfer its caught fish, it will always use this card to make a transaction. It contains the Private Key used to sign messages, as well as the Endorsement Peers and Orderers that can be addressed by the Fischer AG client. We note that proper storage of this card is particularly critical in terms of security. In addition, secure distribution is neither trivial nor particularly user-friendly. To improve usability, Hyperledger Composer provides its internal REST server – a middleware used to access the underlying Fabric network. The REST server makes it possible to store the cards of the individual participants in dedicated wallets and use standard protocols such as OAuth 2.0, SAML or OpenID Connect for authentication. This makes it very easy for Fischer AG applications to participate in the network; but we should remember that this actually contradicts the desired decentralized infrastructure. The REST server has full power over the cards of all participants and is therefore a central trust center – a function which is actually not needed. As is so often the case, this is a trade-off between usability and security.

Conclusion

We hope that this article has provided you with a comprehensive overview of the benefits and uses of Hyperledger Fabric. Experience has shown us that tools such as Hyperledger Composer make it easy to quickly implement a business application on Hyperledger Fabric. As a result, this very complex technology becomes suitable for everyday use in software development. The community is already very big, and you can look forward to the upcoming releases. In particular, the alternative implementation to the Orderer concept, should be yet another milestone in the Hyperledger universe.

 

Links & literature

[1] https://www.tradelens.com/

STAY TUNED!

BEHIND THE TRACKS

Blockchain Advanced Development

Advanced step-by-step technical guide: Sharing the know-how

Blockchain Impact & Strategy

Experimenting with blockchain technology: Real-world inspiring use cases

Blockchain Technology 101

Principles, tools–frameworks & libraries–and implementation