Reputation: 142
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
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
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