mirror of
https://github.com/corda/corda.git
synced 2024-12-21 13:57:54 +00:00
Add a doc on writing a custom notary
This commit is contained in:
parent
2973755bc8
commit
9e563f9b98
@ -0,0 +1,89 @@
|
|||||||
|
package net.corda.notarydemo
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.core.contracts.TransactionVerificationException
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.node.PluginServiceHub
|
||||||
|
import net.corda.core.node.services.CordaService
|
||||||
|
import net.corda.core.node.services.TimeWindowChecker
|
||||||
|
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||||
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
|
import net.corda.core.transactions.SignedTransaction
|
||||||
|
import net.corda.core.transactions.WireTransaction
|
||||||
|
import net.corda.core.utilities.unwrap
|
||||||
|
import net.corda.flows.*
|
||||||
|
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||||
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
|
import java.security.SignatureException
|
||||||
|
|
||||||
|
// START 1
|
||||||
|
@CordaService
|
||||||
|
class MyCustomValidatingNotaryService(override val services: PluginServiceHub) : TrustedAuthorityNotaryService() {
|
||||||
|
companion object {
|
||||||
|
val type = ValidatingNotaryService.type.getSubType("mycustom")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val timeWindowChecker = TimeWindowChecker(services.clock)
|
||||||
|
override val uniquenessProvider = PersistentUniquenessProvider()
|
||||||
|
|
||||||
|
override fun createServiceFlow(otherParty: Party, platformVersion: Int): FlowLogic<Void?> {
|
||||||
|
return MyValidatingNotaryFlow(otherParty, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun start() {}
|
||||||
|
override fun stop() {}
|
||||||
|
}
|
||||||
|
// END 1
|
||||||
|
|
||||||
|
// START 2
|
||||||
|
class MyValidatingNotaryFlow(otherSide: Party, service: MyCustomValidatingNotaryService) : NotaryFlow.Service(otherSide, service) {
|
||||||
|
/**
|
||||||
|
* The received transaction is checked for contract-validity, which requires fully resolving it into a
|
||||||
|
* [TransactionForVerification], for which the caller also has to to reveal the whole transaction
|
||||||
|
* dependency chain.
|
||||||
|
*/
|
||||||
|
@Suspendable
|
||||||
|
override fun receiveAndVerifyTx(): TransactionParts {
|
||||||
|
val stx = receive<SignedTransaction>(otherSide).unwrap { it }
|
||||||
|
checkSignatures(stx)
|
||||||
|
val wtx = stx.tx
|
||||||
|
validateTransaction(wtx)
|
||||||
|
val ltx = validateTransaction(wtx)
|
||||||
|
processTransaction(ltx)
|
||||||
|
|
||||||
|
return TransactionParts(wtx.id, wtx.inputs, wtx.timeWindow)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processTransaction(ltx: LedgerTransaction) {
|
||||||
|
// Add custom transaction processing logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkSignatures(stx: SignedTransaction) {
|
||||||
|
try {
|
||||||
|
stx.verifySignatures(serviceHub.myInfo.notaryIdentity.owningKey)
|
||||||
|
} catch(e: SignedTransaction.SignaturesMissingException) {
|
||||||
|
throw NotaryException(NotaryError.SignaturesMissing(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
fun validateTransaction(wtx: WireTransaction): LedgerTransaction {
|
||||||
|
try {
|
||||||
|
resolveTransaction(wtx)
|
||||||
|
val ltx = wtx.toLedgerTransaction(serviceHub)
|
||||||
|
ltx.verify()
|
||||||
|
return ltx
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw when (e) {
|
||||||
|
is TransactionVerificationException -> NotaryException(NotaryError.TransactionInvalid(e.toString()))
|
||||||
|
is SignatureException -> NotaryException(NotaryError.SignaturesInvalid(e.toString()))
|
||||||
|
else -> e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
private fun resolveTransaction(wtx: WireTransaction) = subFlow(ResolveTransactionsFlow(wtx, otherSide))
|
||||||
|
}
|
||||||
|
// END 2
|
32
docs/source/tutorial-custom-notary.rst
Normal file
32
docs/source/tutorial-custom-notary.rst
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
.. highlight:: kotlin
|
||||||
|
|
||||||
|
Writing a custom notary service
|
||||||
|
===============================
|
||||||
|
|
||||||
|
.. warning:: Customising a notary service is an advanced feature and not recommended for most use-cases. Currently,
|
||||||
|
customising Raft or BFT notaries is not yet fully supported. If you want to write your own Raft notary you will have to
|
||||||
|
implement a custom database connector (or use a separate database for the notary), and use a custom configuration file.
|
||||||
|
|
||||||
|
Similarly to writing an oracle service, the first step is to create a service class in your CorDapp and annotate it
|
||||||
|
with ``@CordaService``. The Corda node scans for any class with this annotation and initialises them. The only requirement
|
||||||
|
is that the class provide a constructor with a single parameter of type ``PluginServiceHub``.
|
||||||
|
|
||||||
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/CustomNotaryTutorial.kt
|
||||||
|
:language: kotlin
|
||||||
|
:start-after: START 1
|
||||||
|
:end-before: END 1
|
||||||
|
|
||||||
|
The next step is to write a notary service flow. 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:
|
||||||
|
|
||||||
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/CustomNotaryTutorial.kt
|
||||||
|
:language: kotlin
|
||||||
|
:start-after: START 2
|
||||||
|
:end-before: END 2
|
||||||
|
|
||||||
|
To ensure the custom notary is installed and advertised by the node, specify it in the configuration file:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
extraAdvertisedServiceIds : ["corda.notary.validating.mycustom"]
|
Loading…
Reference in New Issue
Block a user