Usage Restrictions of Chaincode Expressions

The main goal of any blockchain network is to reach consensus. In other words, every honest member in the network should have the same chain of valid transactions, which should result in the same distributed ledger.

In a Hyperledger Fabric network, peers run chaincodes to make a decision on whether a transaction is correct or not. Thus, a chaincode developer should avoid any logic in the chaincode that can yield different outcomes on multiple peers during the endorsement phase.

These expressions include date-time evaluation, generation of random values, peer-specific information usage, collecting data from external sources, etc. We will discuss them separately and provide examples of non-deterministic behavior below.

  • Date-time evaluation

    It is pretty common for regular applications to log the date and time of record submission. Let’s assume that we want to store a state that contains the timestamp field along with other information. For most developers, an intuitive approach is to fill the timestamp right into the chaincode using the code below.

    record.timestamp = new Date()

    However, this approach is likely to lead to an endorsement failure if multiple signatures are required to endorse. This will happen due to the latency in the network: the code sample above will result in different values on different peers, causing them to have different write sets.

    A proper solution to this issue is to simply pass the timestamp from an application as an argument to a chaincode call.

  • Generation of random values

    Imagine you want to generate a random UUID for every record that will be stored in the ledger. For this purpose, you decided to utilize the uuid npm package.

    const { uuidv4 } = require('uuid/v4'); const uuid = uuidv4();

    The uuid generator is based on Math.random(), which, in turn, has a time-based seed. Therefore, we can foresee the same issue as before: due to the latency in the network, we cannot obtain the same write sets on different peers because of the unequal seeds generating completely different sequences. How can we randomize anything in the blockchain network then?

    While the approach of passing an ID as a parameter to the chaincode call is still working, we can choose another tactic, as well. We can utilize a seeded UUID generator. It is possible to specify a chaincode initialization function, where we can create a constant seed and save it into the ledger. Then, it can be retrieved by any peer to generate a random sequence.

    Furthermore, you can deterministically rewrite the seed causing your randomizer to change the output sequence over time.

  • Peer-specific information usage

    It is quite obvious that different peers can have different configurations, so the chaincode write set should not be based on any hardware or software characteristics of the peer both directly and indirectly, including the operating system, number of cores, side script or request processing execution time, etc.

  • Collecting data from external sources

    Let’s consider an example of a GET request collecting the exchange rates from an external oracle.

    http.get('https://example.com/exchange-rate', (res) => { /* process response */ });

    The response body can further be parsed to retrieve the actual data that can be used for currency conversion.

    Such expressions cannot be as reliable as expected. Oracles can dynamically change the output reflecting real-world changes (e.g., currencies exchange rates, weather forecast, etc.). This can result in an endorsement failure.

    If the oracle’s update frequency is not high, then we can still use it by simply performing multiple chaincode calls if an error occurs. Though, it is not the only thing that we should worry about when using external data sources. Since Hyperledger Fabric networks are enterprise-oriented, the request coming from a peer can be blocked by the organization’s firewall. That is why we should be careful and use only agreed data sources in the chaincode.

    🚩Oracles can return static or rarely changing data, such as postal or phone codes for a specific region. Such oracles should be safe to rely on from a chaincode perspective, but you should still take the accessibility issue into consideration.

In conclusion, you should consider the distributed system issues while developing a chaincode or an application for a blockchain network. It is necessary to test functionality on different endorsement policies, as well.

Last updated

Was this helpful?