Writing a custom notary service (experimental)

This tutorial covers how to write a custom notary service.

The first step in creating a custom notary service is to create a service class in your CorDapp that extends the NotaryService abstract class. This will ensure that it is recognised as a notary service. The custom notary service class should provide a constructor with two parameters of types ServiceHubInternal and PublicKey. Note that ServiceHubInternal does not provide any API stability guarantees.

class MyCustomValidatingNotaryService(
        override val services: ServiceHubInternal,
        override val notaryIdentityKey: PublicKey)
    : SinglePartyNotaryService() {
    override val uniquenessProvider = PersistentUniquenessProvider(
            services.clock,
            services.database,
            services.cacheFactory,
            ::signTransaction)

    override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?> = MyValidatingNotaryFlow(otherPartySession, this)

    override fun start() {}
    override fun stop() {}
}

MyCustomNotaryService.kt

The next step is to write a flow for the custom notary service. You are free to copy and modify the existing built-in flows such as ValidatingNotaryFlow, NonValidatingNotaryFlow, or implement your own from scratch (following the NotaryFlow.Service template). Below is an example of a custom flow for a validating notary service:

class MyValidatingNotaryFlow(otherSide: FlowSession, service: MyCustomValidatingNotaryService) : ValidatingNotaryFlow(otherSide, service) {
    override fun verifyTransaction(requestPayload: NotarisationPayload) {
        try {
            val stx = requestPayload.signedTransaction
            resolveAndContractVerify(stx)
            verifySignatures(stx)
            customVerify(stx)
        } catch (e: Exception) {
            throw  NotaryInternalException(NotaryError.TransactionInvalid(e))
        }
    }

    @Suspendable
    private fun resolveAndContractVerify(stx: SignedTransaction) {
        subFlow(ResolveTransactionsFlow(stx, otherSideSession))
        stx.verify(serviceHub, false)
    }

    private fun verifySignatures(stx: SignedTransaction) {
        val transactionWithSignatures = stx.resolveTransactionWithSignatures(serviceHub)
        checkSignatures(transactionWithSignatures)
    }

    private fun checkSignatures(tx: TransactionWithSignatures) {
        tx.verifySignaturesExcept(service.notaryIdentityKey)
    }

    private fun customVerify(stx: SignedTransaction) {
        // Add custom verification logic
    }
}

MyCustomNotaryService.kt

To enable the custom notary service, add the following to the node configuration:

notary : {
    validating : true # Set to false if your service is non-validating
    className : "net.corda.notarydemo.MyCustomValidatingNotaryService" # The fully qualified name of your service class
}

To create a flow test that uses your custom notary service, you can set the class name of the custom notary service as follows in your flow test:

        mockNet = MockNetwork(MockNetworkParameters(
                cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()),
                notarySpecs = listOf(MockNetworkNotarySpec(
                        name = CordaX500Name("Custom Notary", "Amsterdam", "NL"),
                        className = "net.corda.testing.node.CustomNotaryTest\$CustomNotaryService",
                        validating = false // Can also be validating if preferred.
                ))
        ))

CustomNotaryTest.kt

After this, your custom notary will be the default notary on the mock network, and can be used in the same way as described in Write integration tests.

Was this page helpful?

Thanks for your feedback!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.

We're sorry this page wasn't helpful. Let us know how we can make it better!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Create an issue

Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.