Contract Operations API and Ledger Adapters

To manage contracts specified using CSL on various ledger backends, Deon Digital provides various software adapters to virtualize the ledger used to store the contracts via a contract management abstraction (API). The interface for contract management is specified in com.deondigital.sic.ContractOperations, implemented in the following ledger adapters:

  1. Centralized ledger adapter (com.deondigital.sic.DbLedgerContractOperations in sic-dbledger-operations library jar)

  2. Decentralized ledger adapter (com.deondigital.sic.CordaContractOperations in sic-corda-operations library jar)

The application has a free choice of the ledger adapter depending on the ledger technology employed in the application architecture. Since CSL is independent of the underlying ledger details, CSL contracts and reports are completely portable across the different ledger backends by simply switching the ledger adapter. Note that ContractOperations is a typed interface and is coupled to the CSL contracts and reports it manages to ensure compile time checks can be leveraged by the application. For more details on the types and how to generate them from CSL, please refer to the code generator guide.

Note that the contract operations API does not create yet another abstraction of a distributed ledger over various supported ledger technologies. Such a design choice would require knowledge of what constitutes a good ledger abstraction and choice of tradeoffs in the implementation of the abstraction. Instead, we assume the application knows best about the ledger technology it uses. This allows us to implement low-cost adapters that maintain the guarantees (e.g., security, consistency, failure, etc.) of the underlying ledger while providing a uniform API to manage contracts across the ledgers.

Functionality

The functionality of the ledger adapters focus on lifecycle management of the contract in addition to their administration. They provide the view of a secure immutable ledger that stores contracts and allows management of their lifecycle based on the contract specification in a verifiable manner.

Contract Lifecycle Management

The contract management interface supports the following functionality:

Function

Description

instantiate

Instantiate contract on the ledger

applyEvent

Apply event on an instantiated contract

getContractEvents

Retrieve events applied on a contract

getContracts

Retrieve all contracts stored on the ledger

terminateContract

Terminate a contract

novateContract

Novate a contract, i.e., terminate a contract and replace it by instantiating a new contract. This happens atomically.

nextEvents

Compute the set of possible next events that can be applied to a contract in its present state

execute

Instantiate and apply events on many contracts atomically

Note that the above functionality is exposed via an asynchronous interface which allows the caller to chain and synchronize as it deems fit.

Report Generation

The contract management interface also support the following reporting functionality:

Property

Description

reports

Compute reports by accessing this property. The reports written in CSL are available as Kotlin functions under this property.

Since the contract management API abstracts a ledger which manages identities, the ContractOperations API also exposes functions to retrieve stored identities on the ledger and to convert identities from the CSL representation to the ledger’s representation.

Subscribing to Contract Changes (Experimental)

The contract management interface also supports the following experimental subscription functionality:

Property

Description

onContractUpdated

Subscribe to changes in contracts stored in the underlying ledger

This functionality is not standardized yet using the ContractOperations interface, but is an experimental one supported by the the ledger adapters. The ledger adapters allow registration of callback functions that are invoked when a change happens in the ledger to a contract. A contract in the ledger is immutable and every change to it is tagged with a monotonically increasing version number. The registered callback function is invoked with arguments that describe the change and the version number. Due to its experimental nature, the subscription API is not uniform across the ledger adapters.

Consistency Model

The ContractOperations API is thread-safe and every API invocation is atomic and provides both all-or-nothing atomicity and before-or-after atomicity. In the case of a replicated ledger, APIs that perform a change in the ledger are guaranteed to be sequentially consistent while APIs that read from the ledger are guaranteed to be eventually consistent. Note that these guarantees are not baked into ContractOperations API but are a consequence of the low-cost implementation of an atomic API in the ledger adapters which expose the replication model of the ledger. To ensure programming ease, ContractOperations will provide an atomic API but the consistency guarantees under replication can vary across the ledger adapters in the future.

Failure Model

The failure model of ContractOperations API is dependent on the failure model of the underlying ledger that is used in the application architecture.

DbLedger

The centralized ledger (DbLedger) adopts a single publisher and multiple subscriber architecture. The single publisher node must not fail for operations that change the ledger to be successful while operations that read the ledger can be serviced with the local subscriber node even when the publisher node or other subscriber nodes are not available. Any operation that is successful is also guaranteed to be durable.

Corda

The decentralized ledger (Corda) also adopts a similar architecture where a notary node (or cluster) records the order of consumption of various states in the ledger and validates transactions that consume states on the ledger. The notary node, which is used to instantiate the contract, and the local replica node must be available for operations that change the ledger.