Add MockNet support for custom Notary class

This commit is contained in:
Matthijs van den Bos 2019-07-12 13:27:21 +02:00 committed by Mike Hearn
parent 70b2a94fda
commit 100457afc0
5 changed files with 97 additions and 4 deletions

View File

@ -41,6 +41,8 @@ Version 5.0
Version 4.2
-----------
* The MockNet now supports setting a custom Notary class name, as was already supported by normal node config. See :doc:`tutorial-custom-notary`.
* Contract attachments are now automatically whitelisted by the node if another contract attachment is present with the same contract classes,
signed by the same public keys, and uploaded by a trusted uploader. This allows the node to resolve transactions that use earlier versions
of a contract without having to manually install that version, provided a newer version is installed. Similarly, non-contract attachments

View File

@ -32,4 +32,17 @@ To enable the 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
}
}
Testing your custom notary service
---------------------------------
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:
.. literalinclude:: ../../testing/node-driver/src/test/kotlin/net/corda/testing/node/CustomNotaryTest.kt
:language: kotlin
:start-after: START 1
:end-before: END 1
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 :doc:`flow-testing`.

View File

@ -123,8 +123,9 @@ data class MockNetworkParameters(
*
* @property name The name of the notary node.
* @property validating Boolean for whether the notary is validating or non-validating.
* @property className String the optional name of a notary service class to load. If null, a builtin notary is loaded.
*/
data class MockNetworkNotarySpec(val name: CordaX500Name, val validating: Boolean = true) {
data class MockNetworkNotarySpec(val name: CordaX500Name, val validating: Boolean = true, val className: String? = null) {
constructor(name: CordaX500Name) : this(name, validating = true)
}

View File

@ -249,10 +249,10 @@ open class InternalMockNetwork(cordappPackages: List<String> = emptyList(),
@VisibleForTesting
internal open fun createNotaries(): List<TestStartedNode> {
return notarySpecs.map { (name, validating) ->
return notarySpecs.map { (name, validating, className) ->
createNode(InternalMockNodeParameters(
legalName = name,
configOverrides = { doReturn(NotaryConfig(validating)).whenever(it).notary }
configOverrides = { doReturn(NotaryConfig(validating, className = className)).whenever(it).notary }
))
}
}

View File

@ -0,0 +1,77 @@
package net.corda.testing.node
import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSession
import net.corda.core.flows.NotaryFlow
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.notary.NotaryService
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.ServiceHubInternal
import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.DUMMY_CONTRACTS_CORDAPP
import net.corda.testing.node.internal.enclosedCordapp
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.security.PublicKey
import java.util.*
class CustomNotaryTest {
private lateinit var mockNet: MockNetwork
private lateinit var notaryNode: StartedMockNode
private lateinit var aliceNode: StartedMockNode
private lateinit var notary: Party
private lateinit var alice: Party
@Before
fun setup() {
// START 1
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.
))
))
// END 1
aliceNode = mockNet.createPartyNode(ALICE_NAME)
notaryNode = mockNet.defaultNotaryNode
notary = mockNet.defaultNotaryIdentity
alice = aliceNode.info.singleIdentity()
}
@After
fun tearDown() {
mockNet.stopNodes()
}
@Test(expected = CustomNotaryException::class)
fun `custom notary service is active`() {
val tx = DummyContract.generateInitial(Random().nextInt(), notary, alice.ref(0))
val stx = aliceNode.services.signInitialTransaction(tx)
val future = aliceNode.startFlow(NotaryFlow.Client(stx))
mockNet.runNetwork()
future.getOrThrow()
}
class CustomNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : NotaryService() {
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?> =
object : FlowLogic<Void?>() {
override fun call(): Void? {
throw CustomNotaryException("Proof that a custom notary service is running!")
}
}
override fun start() {}
override fun stop() {}
}
class CustomNotaryException(message: String) : FlowException(message)
}