vkoukou
vkoukou

Reputation: 142

Corda Service Failed to Instantiate

I have created a custom Service that I want to run on the node startup and create a default Account if the Account does not exist.

My class:

import com.r3.corda.lib.accounts.workflows.services.AccountService
import com.r3.corda.lib.accounts.workflows.services.KeyManagementBackedAccountService
import net.corda.core.node.AppServiceHub
import net.corda.core.node.services.CordaService
import net.corda.core.serialization.SingletonSerializeAsToken

@CordaService
class MyIdentityService(private val serviceHub: AppServiceHub) : SingletonSerializeAsToken() {
    init {
        val numberOfResults: Int = serviceHub.cordaService(KeyManagementBackedAccountService::class.java).accountInfo("acctName").size

        when(numberOfResults){
            0 -> {  println("Identity service account does not exist, account is being created...")
                    serviceHub.cordaService(KeyManagementBackedAccountService::class.java).createAccount("acctName")
                    println("Identity service account created.")
                }
            else -> println("Identity service account already exists.")
        }
    }
}

The error log during node startup:

Identity service account does not exist, account is being created...
[ERROR] 04:53:44+0100 [main] internal.Node. - Corda service com.example.flows.MyIdentityService failed to instantiate. 
Reason was: null [errorCode=1gal9sv, moreInformationAt=https://errors.corda.net/OS/4.3-RC01/1gal9sv]

The error log is not that helpful in finding the root cause.

Is there something wrong with my Service definition?
Has anyone encountered a similar error using a custom Service?

Upvotes: 0

Views: 343

Answers (2)

Haisheng Zhang
Haisheng Zhang

Reputation: 51

In Corda, there is no promise about the initialisation order for multiple @CordaService instances.

Corda just go through all of the CorDapps in cordapps/ folder and search @CordaService and initialise them as a single instance services in Corda process. In some cases, the order might be always the same, but it is not promised, especially for cross platform.

So back to your question: do the account check and creation after init phase.

Upvotes: 1

vkoukou
vkoukou

Reputation: 142

Although this might be considered a workaround and not a solution, I tackled the issue by removing the code from the init block and created a function that I call from my flow.

I was not able to figure out why running the code from inside init returned an error, I assume the code is executed early and not all the classes have been properly loaded.

Updated code is:

@CordaService
class MyIdentityService(private val serviceHub: AppServiceHub) : SingletonSerializeAsToken() {
    init {
        println("Identity Service is alive!")
    }

    @Suspendable
    fun createIdentityServiceAccount() : StateAndRef<AccountInfo> {
        val name: String = "myacctName"

        try {
            require(serviceHub.cordaService(KeyManagementBackedAccountService::class.java).accountInfo(name).none
            { it.state.data.host == serviceHub.myInfo.legalIdentities.first() })
            { "There is already an account registered with the specified name $name." }
        } catch (ex: Exception){
           println(ex.message)
           return serviceHub.cordaService(KeyManagementBackedAccountService::class.java).accountInfo(name).get(0)
        }
        return serviceHub.accountService.createAccount(name).toCompletableFuture().getOrThrow()
    }
}

Upvotes: 0

Related Questions