Corda 5 developer preview 1 – Corda Services

Corda Nov 15 2021 By: Iryna Tsimashenka
Comments

0 Comments

Views

1,128 Views

Corda 5 developer preview – Corda Services
Iryna Tsimashenka
Iryna Tsimashenka Developer Relations Lead – EMEA/India
Share this post:
Copied

One of the main differences between the Corda 5 Developer Preview 1 (C5DP1) and Corda 4.x is C5DP1 has a layered approach with interface-based APIs, rather than the Corda 4 core module, where implementation and the API formed a single block. In this blog, we will discuss the way we write and use CordaService in Corda 5. CordaService provides a way to use interface-based APIs.

In C5DP1, Functional Corda Services replaces ServiceHub. Therefore, if you need to use a particular Functional Corda Services API, you just inject that Service, rather than including a whole core module. For example, the FlowEngine Service contains basic flow operations that used to be in FlowLogic in Corda 4.x.

Here are CordaService rules:

  • All interactions with Corda API are via Services.
  • A new @CordaInject annotation is used to inject Corda Services at runtime.
  • A variable annotated with @CordaInject must be mutable, which is not final in Java and lateinit in Kotlin.
  • Services must be injected before the call(), which means they can not be used in the constructor.
  • List of all Corda Services.
  • CordaServices are singletons.

Custom CordaService in C5

Custom CordaService provides functional reusability, where the same functionality can be used in different flows by encapsulating its implementation into separate Service and calling it on demand.

Custom CordaService has the exact injection mechanism as CordaServices. Here’s a comparison of Custom CordaService in Corda 4.x and in Corda 5:

In Corda 4.x Custom Corda Service has to implement an abstract class SingletonSerizlizeAsToken and has a single constructor argument AppServiceHub:


@CordaService
class CustomService (val services: AppServiceHub):    SingletonSerializeAsToken(){
 fun fun1(){ //code }
}

In Corda 5 it’s quite different: implementation and takes care of singleton.


interface CustomService : CordaService, CordaFlowInjectable{
 fun doStuff1()
}

The following code snippet is the definition and implementation of CordaServices CustomServiceImpl, it uses @CordaInject — to show that Corda Services can be used by other Services in its implementation:


class CustomServiceImpl: CustomService {
 @CordaInject
 lateinit car vaultStateEventService : VaultStateEventService
 override fun doStuff1(){//code}
}

VaultStateEventService is injected after the construction of Custom Service. For the Custom Service to work, you need to: 

  • Implement the CordaService interface. 
  • Create a unique interface name for each Service. 

If you need your Custom CordaService to be injectable into flow, it must implement CordaFlowInjectable, or implement CordaServiceInjectable to be injectable into other services. If you implement both abstract classes, your Custom CordaService becomes injectable into both flows and services. However, if you only need your custom service to listen for events, you don’t need to implement it.

Using Custom Services

In Corda 4.x usage of Custom Services is:


class Flow1 {
 @Suspendable
 override fun call(){
   val service1=serviceHub.cordaService(CustomService::class.java)
   service1.fun1()
 }
}

In Corda 5, it’s a bit different. You need to define the immutable field of custom service and annotate with the @CordaInject service function call has been injected and is available for use in the call() method:


class Flow1 {
 @CordaInject
 lateinit var service1: CustomService

 @Suspendable
 override fun call(){
   service1.fun1()
 }
}

Service lifecycle

Services come with lifecycle dependencies.

Services are not available in the constructor; CordaService can be injected after the instance has been created. 

CordaService implements ServiceLifecycleObserver, which defines the onEvent() method. If you would like your Service to react to an event, you need to implement logic inside this method. There are two types of events — ServiceStart and StateMachineStarted. When the ServiceStart event is fired, the initialization of the Service can begin. StateMachineStarted is fired when Corda Services are initialized and ready. Therefore, injected Services might only be fully functional after the ServiceStart event has been fired.

Service dependencies create an ordering, which may lead to a circular dependency. This problem occurs when the start of two or more services depend on each other. To eliminate circular dependency, Services injected with @CordaInject are not available until the StateMachineStarted event has been fired. If some services need to be injected before the ServiceStart event is fired, these services need to be annotated with @CordaInjectPreStart. Cyclic CordaInjectPreStart dependency is an error.

Iryna Tsimashenka
Iryna Tsimashenka Iryna Tsimashenka is the developer relations lead for EMEA/India at R3, an enterprise blockchain software firm working with a global ecosystem of more than 350 participants across multiple industries from both the private and public sectors to develop on Corda, its open-source blockchain platform, Corda Enterprise, a commercial version of Corda for enterprise usage, and Conclave, a confidential computing platform. Follow Iryna on LinkedIn here.

Leave a Reply

Subscribe to our newsletter to stay up to date on the latest developer news, tools, and articles.