mirror of
https://github.com/corda/corda.git
synced 2025-02-04 02:01:13 +00:00
Adapt Party comparison to use owningKey
Change Party instances to be uniquely identified by the owning key, without taking into account name. This requires that mock node key generation is reworked so that keys for services and the node itself are distinct, otherwise the network map service cannot differentiate them. Signed-off-by: Ross Nicoll <ross.nicoll@r3.com>
This commit is contained in:
parent
e54d6388fd
commit
e383752995
@ -18,12 +18,17 @@ import java.security.PublicKey
|
|||||||
* cluster of Corda nodes. A [Party] representing a distributed service will use a composite key containing all
|
* cluster of Corda nodes. A [Party] representing a distributed service will use a composite key containing all
|
||||||
* individual cluster nodes' public keys. Each of the nodes in the cluster will advertise the same group [Party].
|
* individual cluster nodes' public keys. Each of the nodes in the cluster will advertise the same group [Party].
|
||||||
*
|
*
|
||||||
|
* Note that equality is based solely on the owning key.
|
||||||
|
*
|
||||||
* @see CompositeKey
|
* @see CompositeKey
|
||||||
*/
|
*/
|
||||||
data class Party(val name: String, val owningKey: CompositeKey) {
|
class Party(val name: String, val owningKey: CompositeKey) {
|
||||||
/** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */
|
/** A helper constructor that converts the given [PublicKey] in to a [CompositeKey] with a single node */
|
||||||
constructor(name: String, owningKey: PublicKey) : this(name, owningKey.composite)
|
constructor(name: String, owningKey: PublicKey) : this(name, owningKey.composite)
|
||||||
|
|
||||||
|
/** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */
|
||||||
|
override fun equals(other: Any?): Boolean = other is Party && this.owningKey == other.owningKey
|
||||||
|
override fun hashCode(): Int = owningKey.hashCode()
|
||||||
override fun toString() = name
|
override fun toString() = name
|
||||||
|
|
||||||
fun ref(bytes: OpaqueBytes) = PartyAndReference(this, bytes)
|
fun ref(bytes: OpaqueBytes) = PartyAndReference(this, bytes)
|
||||||
|
@ -18,6 +18,10 @@ data class NodeInfo(val address: SingleMessageRecipient,
|
|||||||
val legalIdentity: Party,
|
val legalIdentity: Party,
|
||||||
var advertisedServices: List<ServiceEntry> = emptyList(),
|
var advertisedServices: List<ServiceEntry> = emptyList(),
|
||||||
val physicalLocation: PhysicalLocation? = null) {
|
val physicalLocation: PhysicalLocation? = null) {
|
||||||
|
init {
|
||||||
|
require(advertisedServices.none { it.identity == legalIdentity }) { "Service identities must be different from node legal identity" }
|
||||||
|
}
|
||||||
|
|
||||||
val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity
|
val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity
|
||||||
fun serviceIdentities(type: ServiceType): List<Party> = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity }
|
fun serviceIdentities(type: ServiceType): List<Party> = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.docs
|
package net.corda.docs
|
||||||
|
|
||||||
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -9,6 +10,7 @@ import net.corda.core.utilities.DUMMY_NOTARY
|
|||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||||
import net.corda.flows.CashCommand
|
import net.corda.flows.CashCommand
|
||||||
import net.corda.flows.CashFlow
|
import net.corda.flows.CashFlow
|
||||||
|
import net.corda.core.node.ServiceEntry
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
import net.corda.node.utilities.databaseTransaction
|
import net.corda.node.utilities.databaseTransaction
|
||||||
@ -27,10 +29,11 @@ class FxTransactionBuildTutorialTest {
|
|||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
net = MockNetwork(threadPerNode = true)
|
net = MockNetwork(threadPerNode = true)
|
||||||
|
val notaryService = ServiceInfo(ValidatingNotaryService.type)
|
||||||
notaryNode = net.createNode(
|
notaryNode = net.createNode(
|
||||||
legalName = DUMMY_NOTARY.name,
|
legalName = DUMMY_NOTARY.name,
|
||||||
keyPair = DUMMY_NOTARY_KEY,
|
overrideServices = mapOf(Pair(notaryService, DUMMY_NOTARY_KEY)),
|
||||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type)))
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), notaryService))
|
||||||
nodeA = net.createPartyNode(notaryNode.info.address)
|
nodeA = net.createPartyNode(notaryNode.info.address)
|
||||||
nodeB = net.createPartyNode(notaryNode.info.address)
|
nodeB = net.createPartyNode(notaryNode.info.address)
|
||||||
FxTransactionDemoTutorial.registerFxProtocols(nodeA.services)
|
FxTransactionDemoTutorial.registerFxProtocols(nodeA.services)
|
||||||
|
@ -4,6 +4,7 @@ import net.corda.core.contracts.LinearState
|
|||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
|
import net.corda.core.node.ServiceEntry
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.linearHeadsOfType
|
import net.corda.core.node.services.linearHeadsOfType
|
||||||
@ -35,10 +36,11 @@ class WorkflowTransactionBuildTutorialTest {
|
|||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
net = MockNetwork(threadPerNode = true)
|
net = MockNetwork(threadPerNode = true)
|
||||||
|
val notaryService = ServiceInfo(ValidatingNotaryService.type)
|
||||||
notaryNode = net.createNode(
|
notaryNode = net.createNode(
|
||||||
legalName = DUMMY_NOTARY.name,
|
legalName = DUMMY_NOTARY.name,
|
||||||
keyPair = DUMMY_NOTARY_KEY,
|
overrideServices = mapOf(Pair(notaryService, DUMMY_NOTARY_KEY)),
|
||||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type)))
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), notaryService))
|
||||||
nodeA = net.createPartyNode(notaryNode.info.address)
|
nodeA = net.createPartyNode(notaryNode.info.address)
|
||||||
nodeB = net.createPartyNode(notaryNode.info.address)
|
nodeB = net.createPartyNode(notaryNode.info.address)
|
||||||
FxTransactionDemoTutorial.registerFxProtocols(nodeA.services)
|
FxTransactionDemoTutorial.registerFxProtocols(nodeA.services)
|
||||||
|
@ -3,6 +3,14 @@ Release notes
|
|||||||
|
|
||||||
Here are brief summaries of what's changed between each snapshot release.
|
Here are brief summaries of what's changed between each snapshot release.
|
||||||
|
|
||||||
|
Milestone 8
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* API:
|
||||||
|
|
||||||
|
* ``Party`` equality is now based on the owning key, rather than the owning key and name. This is important for
|
||||||
|
party anonymisation to work, as each key must identify exactly one party.
|
||||||
|
|
||||||
Milestone 7
|
Milestone 7
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -29,12 +29,12 @@ class IssuerFlowTest {
|
|||||||
fun `test issuer flow`() {
|
fun `test issuer flow`() {
|
||||||
net = MockNetwork(false, true)
|
net = MockNetwork(false, true)
|
||||||
ledger {
|
ledger {
|
||||||
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
bankOfCordaNode = net.createPartyNode(notaryNode.info.address, BOC.name, BOC_KEY)
|
bankOfCordaNode = net.createPartyNode(notaryNode.info.address, BOC.name)
|
||||||
bankClientNode = net.createPartyNode(notaryNode.info.address, MEGA_CORP.name, MEGA_CORP_KEY)
|
bankClientNode = net.createPartyNode(notaryNode.info.address, MEGA_CORP.name)
|
||||||
|
|
||||||
// using default IssueTo Party Reference
|
// using default IssueTo Party Reference
|
||||||
val issueToPartyAndRef = MEGA_CORP.ref(OpaqueBytes.Companion.of(123))
|
val issueToPartyAndRef = bankClientNode.info.legalIdentity.ref(OpaqueBytes.Companion.of(123))
|
||||||
val (issuer, issuerResult) = runIssuerAndIssueRequester(1000000.DOLLARS, issueToPartyAndRef)
|
val (issuer, issuerResult) = runIssuerAndIssueRequester(1000000.DOLLARS, issueToPartyAndRef)
|
||||||
assertEquals(issuerResult.get(), issuer.get().resultFuture.get())
|
assertEquals(issuerResult.get(), issuer.get().resultFuture.get())
|
||||||
|
|
||||||
|
@ -275,16 +275,16 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun makeInfo(): NodeInfo {
|
private fun makeInfo(): NodeInfo {
|
||||||
val services = makeServiceEntries()
|
val advertisedServiceEntries = makeServiceEntries()
|
||||||
val legalIdentity = obtainLegalIdentity()
|
val legalIdentity = obtainLegalIdentity()
|
||||||
return NodeInfo(net.myAddress, legalIdentity, services, findMyLocation())
|
return NodeInfo(net.myAddress, legalIdentity, advertisedServiceEntries, findMyLocation())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service entry contains the advertised [ServiceInfo] along with the service identity. The identity *name* is
|
* A service entry contains the advertised [ServiceInfo] along with the service identity. The identity *name* is
|
||||||
* taken from the configuration or, if non specified, generated by combining the node's legal name and the service id.
|
* taken from the configuration or, if non specified, generated by combining the node's legal name and the service id.
|
||||||
*/
|
*/
|
||||||
protected fun makeServiceEntries(): List<ServiceEntry> {
|
protected open fun makeServiceEntries(): List<ServiceEntry> {
|
||||||
return advertisedServices.map {
|
return advertisedServices.map {
|
||||||
val serviceId = it.type.id
|
val serviceId = it.type.id
|
||||||
val serviceName = it.name ?: "$serviceId|${configuration.myLegalName}"
|
val serviceName = it.name ?: "$serviceId|${configuration.myLegalName}"
|
||||||
|
@ -14,11 +14,14 @@ import net.corda.node.services.network.NetworkMapService
|
|||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
|
import net.i2p.crypto.eddsa.KeyPairGenerator
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.math.BigInteger
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
|
import java.security.KeyPairGeneratorSpi
|
||||||
import java.util.jar.JarOutputStream
|
import java.util.jar.JarOutputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -84,8 +87,10 @@ class AttachmentTests {
|
|||||||
// Make a node that doesn't do sanity checking at load time.
|
// Make a node that doesn't do sanity checking at load time.
|
||||||
val n0 = network.createNode(null, -1, object : MockNetwork.Factory {
|
val n0 = network.createNode(null, -1, object : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int,
|
||||||
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) {
|
overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
|
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
override fun start(): MockNetwork.MockNode {
|
override fun start(): MockNetwork.MockNode {
|
||||||
super.start()
|
super.start()
|
||||||
(storage.attachments as NodeAttachmentService).checkAttachmentsOnLoad = false
|
(storage.attachments as NodeAttachmentService).checkAttachmentsOnLoad = false
|
||||||
|
@ -20,7 +20,6 @@ import net.corda.core.transactions.SignedTransaction
|
|||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
|
||||||
import net.corda.core.utilities.LogHelper
|
import net.corda.core.utilities.LogHelper
|
||||||
import net.corda.core.utilities.TEST_TX_TIME
|
import net.corda.core.utilities.TEST_TX_TIME
|
||||||
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
||||||
@ -43,6 +42,7 @@ import org.junit.Test
|
|||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.math.BigInteger
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
@ -60,9 +60,6 @@ import kotlin.test.assertTrue
|
|||||||
*/
|
*/
|
||||||
class TwoPartyTradeFlowTests {
|
class TwoPartyTradeFlowTests {
|
||||||
lateinit var net: MockNetwork
|
lateinit var net: MockNetwork
|
||||||
lateinit var notaryNode: MockNetwork.MockNode
|
|
||||||
lateinit var aliceNode: MockNetwork.MockNode
|
|
||||||
lateinit var bobNode: MockNetwork.MockNode
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun before() {
|
fun before() {
|
||||||
@ -84,9 +81,9 @@ class TwoPartyTradeFlowTests {
|
|||||||
net = MockNetwork(false, true)
|
net = MockNetwork(false, true)
|
||||||
|
|
||||||
ledger {
|
ledger {
|
||||||
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY)
|
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||||
bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY)
|
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||||
val aliceKey = aliceNode.services.legalIdentityKey
|
val aliceKey = aliceNode.services.legalIdentityKey
|
||||||
val notaryKey = notaryNode.services.notaryIdentityKey
|
val notaryKey = notaryNode.services.notaryIdentityKey
|
||||||
|
|
||||||
@ -99,9 +96,10 @@ class TwoPartyTradeFlowTests {
|
|||||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
||||||
|
|
||||||
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey, notaryKey)
|
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey)
|
||||||
|
|
||||||
val (bobStateMachine, aliceResult) = runBuyerAndSeller("alice's paper".outputStateAndRef())
|
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode,
|
||||||
|
"alice's paper".outputStateAndRef())
|
||||||
|
|
||||||
// TODO: Verify that the result was inserted into the transaction database.
|
// TODO: Verify that the result was inserted into the transaction database.
|
||||||
// assertEquals(bobResult.get(), aliceNode.storage.validatedTransactions[aliceResult.get().id])
|
// assertEquals(bobResult.get(), aliceNode.storage.validatedTransactions[aliceResult.get().id])
|
||||||
@ -124,9 +122,9 @@ class TwoPartyTradeFlowTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `shutdown and restore`() {
|
fun `shutdown and restore`() {
|
||||||
ledger {
|
ledger {
|
||||||
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY)
|
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||||
bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY)
|
var bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||||
aliceNode.disableDBCloseOnStop()
|
aliceNode.disableDBCloseOnStop()
|
||||||
bobNode.disableDBCloseOnStop()
|
bobNode.disableDBCloseOnStop()
|
||||||
val aliceKey = aliceNode.services.legalIdentityKey
|
val aliceKey = aliceNode.services.legalIdentityKey
|
||||||
@ -142,8 +140,8 @@ class TwoPartyTradeFlowTests {
|
|||||||
}
|
}
|
||||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
||||||
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey, notaryKey)
|
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey)
|
||||||
val aliceFuture = runBuyerAndSeller("alice's paper".outputStateAndRef()).sellerResult
|
val aliceFuture = runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef()).sellerResult
|
||||||
|
|
||||||
// Everything is on this thread so we can now step through the flow one step at a time.
|
// Everything is on this thread so we can now step through the flow one step at a time.
|
||||||
// Seller Alice already sent a message to Buyer Bob. Pump once:
|
// Seller Alice already sent a message to Buyer Bob. Pump once:
|
||||||
@ -179,10 +177,11 @@ class TwoPartyTradeFlowTests {
|
|||||||
// that Bob was waiting on before the reboot occurred.
|
// that Bob was waiting on before the reboot occurred.
|
||||||
bobNode = net.createNode(networkMapAddr, bobAddr.id, object : MockNetwork.Factory {
|
bobNode = net.createNode(networkMapAddr, bobAddr.id, object : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
return MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, bobAddr.id, BOB_KEY)
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
|
return MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, bobAddr.id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
}, true, BOB.name, BOB_KEY)
|
}, true, BOB.name)
|
||||||
|
|
||||||
// Find the future representing the result of this state machine again.
|
// Find the future representing the result of this state machine again.
|
||||||
val bobFuture = bobNode.smm.findStateMachines(Buyer::class.java).single().second
|
val bobFuture = bobNode.smm.findStateMachines(Buyer::class.java).single().second
|
||||||
@ -213,12 +212,16 @@ class TwoPartyTradeFlowTests {
|
|||||||
|
|
||||||
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
|
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
|
||||||
// of gets and puts.
|
// of gets and puts.
|
||||||
private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: String, keyPair: KeyPair): MockNetwork.MockNode {
|
private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: String, overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNetwork.MockNode {
|
||||||
// Create a node in the mock network ...
|
// Create a node in the mock network ...
|
||||||
return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory {
|
return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
network: MockNetwork,
|
||||||
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) {
|
networkMapAddr: SingleMessageRecipient?,
|
||||||
|
advertisedServices: Set<ServiceInfo>, id: Int,
|
||||||
|
overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
|
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
// That constructs the storage service object in a customised way ...
|
// That constructs the storage service object in a customised way ...
|
||||||
override fun constructStorageService(
|
override fun constructStorageService(
|
||||||
attachments: NodeAttachmentService,
|
attachments: NodeAttachmentService,
|
||||||
@ -229,14 +232,14 @@ class TwoPartyTradeFlowTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, true, name, keyPair)
|
}, true, name, overrideServices)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `check dependencies of sale asset are resolved`() {
|
fun `check dependencies of sale asset are resolved`() {
|
||||||
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name, ALICE_KEY)
|
val aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name)
|
||||||
bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name, BOB_KEY)
|
val bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name)
|
||||||
val aliceKey = aliceNode.services.legalIdentityKey
|
val aliceKey = aliceNode.services.legalIdentityKey
|
||||||
|
|
||||||
ledger(aliceNode.services) {
|
ledger(aliceNode.services) {
|
||||||
@ -250,15 +253,18 @@ class TwoPartyTradeFlowTests {
|
|||||||
}
|
}
|
||||||
val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray()))
|
val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray()))
|
||||||
|
|
||||||
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite, notaryNode.info.notaryIdentity).second
|
val extraKey = bobNode.keyManagement.freshKey()
|
||||||
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode)
|
val bobsFakeCash = fillUpForBuyer(false, extraKey.public.composite,
|
||||||
|
DUMMY_CASH_ISSUER.party,
|
||||||
|
notaryNode.info.notaryIdentity).second
|
||||||
|
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, bobNode.services.legalIdentityKey, extraKey)
|
||||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
|
||||||
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey)
|
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey)
|
||||||
|
|
||||||
net.runNetwork() // Clear network map registration messages
|
net.runNetwork() // Clear network map registration messages
|
||||||
|
|
||||||
runBuyerAndSeller("alice's paper".outputStateAndRef())
|
runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef())
|
||||||
|
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
|
|
||||||
@ -326,9 +332,9 @@ class TwoPartyTradeFlowTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `track() works`() {
|
fun `track() works`() {
|
||||||
|
|
||||||
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name, ALICE_KEY)
|
val aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name)
|
||||||
bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name, BOB_KEY)
|
val bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name)
|
||||||
val aliceKey = aliceNode.services.legalIdentityKey
|
val aliceKey = aliceNode.services.legalIdentityKey
|
||||||
|
|
||||||
ledger(aliceNode.services) {
|
ledger(aliceNode.services) {
|
||||||
@ -342,11 +348,13 @@ class TwoPartyTradeFlowTests {
|
|||||||
}
|
}
|
||||||
val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray()))
|
val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray()))
|
||||||
|
|
||||||
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite, notaryNode.info.notaryIdentity).second
|
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public.composite,
|
||||||
insertFakeTransactions(bobsFakeCash, bobNode)
|
DUMMY_CASH_ISSUER.party,
|
||||||
|
notaryNode.info.notaryIdentity).second
|
||||||
|
insertFakeTransactions(bobsFakeCash, bobNode, notaryNode)
|
||||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
|
||||||
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey)
|
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey)
|
||||||
|
|
||||||
net.runNetwork() // Clear network map registration messages
|
net.runNetwork() // Clear network map registration messages
|
||||||
|
|
||||||
@ -356,7 +364,8 @@ class TwoPartyTradeFlowTests {
|
|||||||
val aliceTxMappings = databaseTransaction(aliceNode.database) {
|
val aliceTxMappings = databaseTransaction(aliceNode.database) {
|
||||||
aliceMappingsStorage.track().second
|
aliceMappingsStorage.track().second
|
||||||
}
|
}
|
||||||
val aliceSmId = runBuyerAndSeller("alice's paper".outputStateAndRef()).sellerId
|
val aliceSmId = runBuyerAndSeller(notaryNode, aliceNode, bobNode,
|
||||||
|
"alice's paper".outputStateAndRef()).sellerId
|
||||||
|
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
|
|
||||||
@ -412,12 +421,15 @@ class TwoPartyTradeFlowTests {
|
|||||||
val sellerId: StateMachineRunId
|
val sellerId: StateMachineRunId
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun runBuyerAndSeller(assetToSell: StateAndRef<OwnableState>): RunResult {
|
private fun runBuyerAndSeller(notaryNode: MockNetwork.MockNode,
|
||||||
val buyerFuture = bobNode.initiateSingleShotFlow(Seller::class) { otherParty ->
|
sellerNode: MockNetwork.MockNode,
|
||||||
|
buyerNode: MockNetwork.MockNode,
|
||||||
|
assetToSell: StateAndRef<OwnableState>): RunResult {
|
||||||
|
val buyerFuture = buyerNode.initiateSingleShotFlow(Seller::class) { otherParty ->
|
||||||
Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java)
|
Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java)
|
||||||
}.map { it.stateMachine }
|
}.map { it.stateMachine }
|
||||||
val seller = Seller(bobNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, ALICE_KEY)
|
val seller = Seller(buyerNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, sellerNode.services.legalIdentityKey)
|
||||||
val sellerResultFuture = aliceNode.services.startFlow(seller).resultFuture
|
val sellerResultFuture = sellerNode.services.startFlow(seller).resultFuture
|
||||||
return RunResult(buyerFuture, sellerResultFuture, seller.stateMachine.id)
|
return RunResult(buyerFuture, sellerResultFuture, seller.stateMachine.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,23 +438,24 @@ class TwoPartyTradeFlowTests {
|
|||||||
aliceError: Boolean,
|
aliceError: Boolean,
|
||||||
expectedMessageSubstring: String
|
expectedMessageSubstring: String
|
||||||
) {
|
) {
|
||||||
notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY)
|
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||||
bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY)
|
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||||
val aliceKey = aliceNode.services.legalIdentityKey
|
val aliceKey = aliceNode.services.legalIdentityKey
|
||||||
val bobKey = bobNode.services.legalIdentityKey
|
val bobKey = bobNode.services.legalIdentityKey
|
||||||
val issuer = MEGA_CORP.ref(1, 2, 3)
|
val issuer = MEGA_CORP.ref(1, 2, 3)
|
||||||
|
|
||||||
val bobsBadCash = fillUpForBuyer(bobError, bobKey.public.composite, notaryNode.info.notaryIdentity).second
|
val bobsBadCash = fillUpForBuyer(bobError, bobKey.public.composite, DUMMY_CASH_ISSUER.party,
|
||||||
|
notaryNode.info.notaryIdentity).second
|
||||||
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.info.legalIdentity.owningKey,
|
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.info.legalIdentity.owningKey,
|
||||||
1200.DOLLARS `issued by` issuer, null, notaryNode.info.notaryIdentity).second
|
1200.DOLLARS `issued by` issuer, null, notaryNode.info.notaryIdentity).second
|
||||||
|
|
||||||
insertFakeTransactions(bobsBadCash, bobNode, bobKey)
|
insertFakeTransactions(bobsBadCash, bobNode, notaryNode, bobKey)
|
||||||
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey)
|
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey)
|
||||||
|
|
||||||
net.runNetwork() // Clear network map registration messages
|
net.runNetwork() // Clear network map registration messages
|
||||||
|
|
||||||
val (bobStateMachine, aliceResult) = runBuyerAndSeller("alice's paper".outputStateAndRef())
|
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode, "alice's paper".outputStateAndRef())
|
||||||
|
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
|
|
||||||
@ -461,9 +474,10 @@ class TwoPartyTradeFlowTests {
|
|||||||
private fun insertFakeTransactions(
|
private fun insertFakeTransactions(
|
||||||
wtxToSign: List<WireTransaction>,
|
wtxToSign: List<WireTransaction>,
|
||||||
node: AbstractNode,
|
node: AbstractNode,
|
||||||
|
notaryNode: MockNetwork.MockNode,
|
||||||
vararg extraKeys: KeyPair): Map<SecureHash, SignedTransaction> {
|
vararg extraKeys: KeyPair): Map<SecureHash, SignedTransaction> {
|
||||||
|
val signed: List<SignedTransaction> = signAll(wtxToSign, extraKeys.toList() + notaryNode.services.notaryIdentityKey + DUMMY_CASH_ISSUER_KEY)
|
||||||
return databaseTransaction(node.database) {
|
return databaseTransaction(node.database) {
|
||||||
val signed: List<SignedTransaction> = signAll(wtxToSign, extraKeys.toList() + DUMMY_CASH_ISSUER_KEY)
|
|
||||||
node.services.recordTransactions(signed)
|
node.services.recordTransactions(signed)
|
||||||
val validatedTransactions = node.services.storageService.validatedTransactions
|
val validatedTransactions = node.services.storageService.validatedTransactions
|
||||||
if (validatedTransactions is RecordingTransactionStorage) {
|
if (validatedTransactions is RecordingTransactionStorage) {
|
||||||
@ -475,20 +489,21 @@ class TwoPartyTradeFlowTests {
|
|||||||
|
|
||||||
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForBuyer(
|
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForBuyer(
|
||||||
withError: Boolean,
|
withError: Boolean,
|
||||||
owner: CompositeKey = BOB_PUBKEY,
|
owner: CompositeKey,
|
||||||
|
issuer: Party,
|
||||||
notary: Party): Pair<Vault, List<WireTransaction>> {
|
notary: Party): Pair<Vault, List<WireTransaction>> {
|
||||||
val issuer = DUMMY_CASH_ISSUER
|
val interimOwnerKey = MEGA_CORP_PUBKEY
|
||||||
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
|
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
|
||||||
// wants to sell to Bob.
|
// wants to sell to Bob.
|
||||||
val eb1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
val eb1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
||||||
// Issued money to itself.
|
// Issued money to itself.
|
||||||
output("elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
|
output("elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` interimOwnerKey }
|
||||||
output("elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
|
output("elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` interimOwnerKey }
|
||||||
if (!withError) {
|
if (!withError) {
|
||||||
command(DUMMY_CASH_ISSUER_KEY.public.composite) { Cash.Commands.Issue() }
|
command(issuer.owningKey) { Cash.Commands.Issue() }
|
||||||
} else {
|
} else {
|
||||||
// Put a broken command on so at least a signature is created
|
// Put a broken command on so at least a signature is created
|
||||||
command(DUMMY_CASH_ISSUER_KEY.public.composite) { Cash.Commands.Move() }
|
command(issuer.owningKey) { Cash.Commands.Move() }
|
||||||
}
|
}
|
||||||
timestamp(TEST_TX_TIME)
|
timestamp(TEST_TX_TIME)
|
||||||
if (withError) {
|
if (withError) {
|
||||||
@ -502,15 +517,15 @@ class TwoPartyTradeFlowTests {
|
|||||||
val bc1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
val bc1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
||||||
input("elbonian money 1")
|
input("elbonian money 1")
|
||||||
output("bob cash 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` owner }
|
output("bob cash 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` owner }
|
||||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
command(interimOwnerKey) { Cash.Commands.Move() }
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
val bc2 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
val bc2 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
|
||||||
input("elbonian money 2")
|
input("elbonian money 2")
|
||||||
output("bob cash 2", notary = notary) { 300.DOLLARS.CASH `issued by` issuer `owned by` owner }
|
output("bob cash 2", notary = notary) { 300.DOLLARS.CASH `issued by` issuer `owned by` owner }
|
||||||
output(notary = notary) { 700.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } // Change output.
|
output(notary = notary) { 700.DOLLARS.CASH `issued by` issuer `owned by` interimOwnerKey } // Change output.
|
||||||
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
command(interimOwnerKey) { Cash.Commands.Move() }
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package net.corda.node.services
|
package net.corda.node.services
|
||||||
|
|
||||||
import net.corda.core.crypto.composite
|
|
||||||
import net.corda.core.crypto.generateKeyPair
|
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.node.services.network.NetworkMapService
|
import net.corda.node.services.network.NetworkMapService
|
||||||
@ -9,6 +7,7 @@ import net.corda.node.utilities.databaseTransaction
|
|||||||
import net.corda.testing.expect
|
import net.corda.testing.expect
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.math.BigInteger
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class InMemoryNetworkMapCacheTest {
|
class InMemoryNetworkMapCacheTest {
|
||||||
@ -24,19 +23,23 @@ class InMemoryNetworkMapCacheTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `key collision`() {
|
fun `key collision`() {
|
||||||
val keyPair = generateKeyPair()
|
val entropy = BigInteger.valueOf(24012017L)
|
||||||
val nodeA = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node A", keyPair, ServiceInfo(NetworkMapService.type))
|
val nodeA = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node A", null, entropy, ServiceInfo(NetworkMapService.type))
|
||||||
val nodeB = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node B", keyPair, ServiceInfo(NetworkMapService.type))
|
val nodeB = network.createNode(null, -1, MockNetwork.DefaultFactory, true, "Node B", null, entropy, ServiceInfo(NetworkMapService.type))
|
||||||
|
assertEquals(nodeA.info.legalIdentity, nodeB.info.legalIdentity)
|
||||||
|
|
||||||
// Node A currently knows only about itself, so this returns node A
|
// Node A currently knows only about itself, so this returns node A
|
||||||
assertEquals(nodeA.netMapCache.getNodeByLegalIdentityKey(keyPair.public.composite), nodeA.info)
|
assertEquals(nodeA.netMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey), nodeA.info)
|
||||||
|
|
||||||
databaseTransaction(nodeA.database) {
|
databaseTransaction(nodeA.database) {
|
||||||
nodeA.netMapCache.addNode(nodeB.info)
|
nodeA.netMapCache.addNode(nodeB.info)
|
||||||
}
|
}
|
||||||
// Now both nodes match, so it throws an error
|
// Now both nodes match, so it throws an error
|
||||||
expect<IllegalStateException> {
|
expect<IllegalStateException> {
|
||||||
nodeA.netMapCache.getNodeByLegalIdentityKey(keyPair.public.composite)
|
nodeA.netMapCache.getNodeByLegalIdentityKey(nodeA.info.legalIdentity.owningKey)
|
||||||
|
}
|
||||||
|
expect<IllegalStateException> {
|
||||||
|
nodeA.netMapCache.getNodeByLegalIdentityKey(nodeB.info.legalIdentity.owningKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ class NotaryChangeTests {
|
|||||||
net = MockNetwork()
|
net = MockNetwork()
|
||||||
oldNotaryNode = net.createNode(
|
oldNotaryNode = net.createNode(
|
||||||
legalName = DUMMY_NOTARY.name,
|
legalName = DUMMY_NOTARY.name,
|
||||||
keyPair = DUMMY_NOTARY_KEY,
|
|
||||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)))
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)))
|
||||||
clientNodeA = net.createNode(networkMapAddress = oldNotaryNode.info.address)
|
clientNodeA = net.createNode(networkMapAddress = oldNotaryNode.info.address)
|
||||||
clientNodeB = net.createNode(networkMapAddress = oldNotaryNode.info.address)
|
clientNodeB = net.createNode(networkMapAddress = oldNotaryNode.info.address)
|
||||||
|
@ -23,6 +23,7 @@ import net.corda.testing.node.MockNetwork
|
|||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.security.KeyPair
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -32,14 +33,15 @@ class NotaryServiceTests {
|
|||||||
lateinit var net: MockNetwork
|
lateinit var net: MockNetwork
|
||||||
lateinit var notaryNode: MockNetwork.MockNode
|
lateinit var notaryNode: MockNetwork.MockNode
|
||||||
lateinit var clientNode: MockNetwork.MockNode
|
lateinit var clientNode: MockNetwork.MockNode
|
||||||
|
lateinit var clientKeyPair: KeyPair
|
||||||
|
|
||||||
@Before fun setup() {
|
@Before fun setup() {
|
||||||
net = MockNetwork()
|
net = MockNetwork()
|
||||||
notaryNode = net.createNode(
|
notaryNode = net.createNode(
|
||||||
legalName = DUMMY_NOTARY.name,
|
legalName = DUMMY_NOTARY.name,
|
||||||
keyPair = DUMMY_NOTARY_KEY,
|
|
||||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)))
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)))
|
||||||
clientNode = net.createNode(networkMapAddress = notaryNode.info.address, keyPair = MINI_CORP_KEY)
|
clientNode = net.createNode(networkMapAddress = notaryNode.info.address)
|
||||||
|
clientKeyPair = clientNode.keyManagement.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single())
|
||||||
net.runNetwork() // Clear network map registration messages
|
net.runNetwork() // Clear network map registration messages
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ class NotaryServiceTests {
|
|||||||
val inputState = issueState(clientNode)
|
val inputState = issueState(clientNode)
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.setTime(Instant.now(), 30.seconds)
|
tx.setTime(Instant.now(), 30.seconds)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
tx.signWith(clientKeyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ class NotaryServiceTests {
|
|||||||
val stx = run {
|
val stx = run {
|
||||||
val inputState = issueState(clientNode)
|
val inputState = issueState(clientNode)
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
tx.signWith(clientKeyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +77,7 @@ class NotaryServiceTests {
|
|||||||
val inputState = issueState(clientNode)
|
val inputState = issueState(clientNode)
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.setTime(Instant.now().plusSeconds(3600), 30.seconds)
|
tx.setTime(Instant.now().plusSeconds(3600), 30.seconds)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
tx.signWith(clientKeyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +91,7 @@ class NotaryServiceTests {
|
|||||||
val stx = run {
|
val stx = run {
|
||||||
val inputState = issueState(clientNode)
|
val inputState = issueState(clientNode)
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
tx.signWith(clientKeyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,13 +109,13 @@ class NotaryServiceTests {
|
|||||||
val inputState = issueState(clientNode)
|
val inputState = issueState(clientNode)
|
||||||
val stx = run {
|
val stx = run {
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
tx.signWith(clientKeyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
val stx2 = run {
|
val stx2 = run {
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.addInputState(issueState(clientNode))
|
tx.addInputState(issueState(clientNode))
|
||||||
tx.signWith(clientNode.keyPair!!)
|
tx.signWith(clientKeyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,9 @@ import net.corda.testing.node.MockNetwork
|
|||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.math.BigInteger
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
|
import java.security.KeyPairGeneratorSpi
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class mirrors [InMemoryNetworkMapServiceTest] but switches in a [PersistentNetworkMapService] and
|
* This class mirrors [InMemoryNetworkMapServiceTest] but switches in a [PersistentNetworkMapService] and
|
||||||
@ -55,8 +57,10 @@ class PersistentNetworkMapServiceTest : AbstractNetworkMapServiceTest() {
|
|||||||
|
|
||||||
private object NodeFactory : MockNetwork.Factory {
|
private object NodeFactory : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int,
|
||||||
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) {
|
overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
|
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
|
|
||||||
override fun makeNetworkMapService() {
|
override fun makeNetworkMapService() {
|
||||||
inNodeNetworkMapService = SwizzleNetworkMapService(services)
|
inNodeNetworkMapService = SwizzleNetworkMapService(services)
|
||||||
|
@ -98,7 +98,6 @@ class ScheduledFlowTests {
|
|||||||
net = MockNetwork(threadPerNode = true)
|
net = MockNetwork(threadPerNode = true)
|
||||||
notaryNode = net.createNode(
|
notaryNode = net.createNode(
|
||||||
legalName = DUMMY_NOTARY.name,
|
legalName = DUMMY_NOTARY.name,
|
||||||
keyPair = DUMMY_NOTARY_KEY,
|
|
||||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type)))
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type)))
|
||||||
nodeA = net.createNode(notaryNode.info.address, start = false)
|
nodeA = net.createNode(notaryNode.info.address, start = false)
|
||||||
nodeB = net.createNode(notaryNode.info.address, start = false)
|
nodeB = net.createNode(notaryNode.info.address, start = false)
|
||||||
|
@ -34,10 +34,9 @@ class ValidatingNotaryServiceTests {
|
|||||||
net = MockNetwork()
|
net = MockNetwork()
|
||||||
notaryNode = net.createNode(
|
notaryNode = net.createNode(
|
||||||
legalName = DUMMY_NOTARY.name,
|
legalName = DUMMY_NOTARY.name,
|
||||||
keyPair = DUMMY_NOTARY_KEY,
|
|
||||||
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type))
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type))
|
||||||
)
|
)
|
||||||
clientNode = net.createNode(networkMapAddress = notaryNode.info.address, keyPair = MINI_CORP_KEY)
|
clientNode = net.createNode(networkMapAddress = notaryNode.info.address)
|
||||||
net.runNetwork() // Clear network map registration messages
|
net.runNetwork() // Clear network map registration messages
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +44,8 @@ class ValidatingNotaryServiceTests {
|
|||||||
val stx = run {
|
val stx = run {
|
||||||
val inputState = issueInvalidState(clientNode, notaryNode.info.notaryIdentity)
|
val inputState = issueInvalidState(clientNode, notaryNode.info.notaryIdentity)
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
val keyPair = clientNode.services.keyManagementService.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single())
|
||||||
|
tx.signWith(keyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,8 @@ class ValidatingNotaryServiceTests {
|
|||||||
|
|
||||||
val command = Command(DummyContract.Commands.Move(), expectedMissingKey)
|
val command = Command(DummyContract.Commands.Move(), expectedMissingKey)
|
||||||
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState, command)
|
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState, command)
|
||||||
tx.signWith(clientNode.keyPair!!)
|
val keyPair = clientNode.services.keyManagementService.toKeyPair(clientNode.info.legalIdentity.owningKey.keys.single())
|
||||||
|
tx.signWith(keyPair)
|
||||||
tx.toSignedTransaction(false)
|
tx.toSignedTransaction(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import net.corda.core.flows.FlowLogic
|
|||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.map
|
import net.corda.core.map
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
|
import net.corda.core.node.services.PartyInfo
|
||||||
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.random63BitValue
|
import net.corda.core.random63BitValue
|
||||||
import net.corda.core.rootCause
|
import net.corda.core.rootCause
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
@ -21,6 +23,7 @@ import net.corda.flows.CashCommand
|
|||||||
import net.corda.flows.CashFlow
|
import net.corda.flows.CashFlow
|
||||||
import net.corda.flows.NotaryFlow
|
import net.corda.flows.NotaryFlow
|
||||||
import net.corda.node.services.persistence.checkpoints
|
import net.corda.node.services.persistence.checkpoints
|
||||||
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
import net.corda.node.utilities.databaseTransaction
|
import net.corda.node.utilities.databaseTransaction
|
||||||
import net.corda.testing.expect
|
import net.corda.testing.expect
|
||||||
import net.corda.testing.expectEvents
|
import net.corda.testing.expectEvents
|
||||||
@ -55,10 +58,12 @@ class StateMachineManagerTests {
|
|||||||
node1 = nodes.first
|
node1 = nodes.first
|
||||||
node2 = nodes.second
|
node2 = nodes.second
|
||||||
val notaryKeyPair = generateKeyPair()
|
val notaryKeyPair = generateKeyPair()
|
||||||
|
val notaryService = ServiceInfo(ValidatingNotaryService.type, "notary-service-2000")
|
||||||
|
val overrideServices = mapOf(Pair(notaryService, notaryKeyPair))
|
||||||
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
|
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
|
||||||
// service addressing.
|
// service addressing.
|
||||||
notary1 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, keyPair = notaryKeyPair, serviceName = "notary-service-2000")
|
notary1 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = "notary-service-2000")
|
||||||
notary2 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, keyPair = notaryKeyPair, serviceName = "notary-service-2000")
|
notary2 = net.createNotaryNode(networkMapAddr = node1.services.myInfo.address, overrideServices = overrideServices, serviceName = "notary-service-2000")
|
||||||
|
|
||||||
net.messagingNetwork.receivedMessages.toSessionTransfers().forEach { sessionTransfers += it }
|
net.messagingNetwork.receivedMessages.toSessionTransfers().forEach { sessionTransfers += it }
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
@ -321,6 +326,8 @@ class StateMachineManagerTests {
|
|||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
}
|
}
|
||||||
val endpoint = net.messagingNetwork.endpoint(notary1.net.myAddress as InMemoryMessagingNetwork.PeerHandle)!!
|
val endpoint = net.messagingNetwork.endpoint(notary1.net.myAddress as InMemoryMessagingNetwork.PeerHandle)!!
|
||||||
|
val party1Info = notary1.services.networkMapCache.getPartyInfo(notary1.info.notaryIdentity)!!
|
||||||
|
assert(party1Info is PartyInfo.Service)
|
||||||
val notary1Address: MessageRecipients = endpoint.getAddressOfParty(notary1.services.networkMapCache.getPartyInfo(notary1.info.notaryIdentity)!!)
|
val notary1Address: MessageRecipients = endpoint.getAddressOfParty(notary1.services.networkMapCache.getPartyInfo(notary1.info.notaryIdentity)!!)
|
||||||
assert(notary1Address is InMemoryMessagingNetwork.ServiceHandle)
|
assert(notary1Address is InMemoryMessagingNetwork.ServiceHandle)
|
||||||
assertEquals(notary1Address, endpoint.getAddressOfParty(notary2.services.networkMapCache.getPartyInfo(notary2.info.notaryIdentity)!!))
|
assertEquals(notary1Address, endpoint.getAddressOfParty(notary2.services.networkMapCache.getPartyInfo(notary2.info.notaryIdentity)!!))
|
||||||
|
@ -22,6 +22,8 @@ import net.corda.node.utilities.databaseTransaction
|
|||||||
import net.corda.testing.initiateSingleShotFlow
|
import net.corda.testing.initiateSingleShotFlow
|
||||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||||
import net.corda.testing.node.MockIdentityService
|
import net.corda.testing.node.MockIdentityService
|
||||||
|
import net.i2p.crypto.eddsa.KeyPairGenerator
|
||||||
|
import java.security.SecureRandom
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -126,7 +128,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
|||||||
showProgressFor(listOf(node1, node2))
|
showProgressFor(listOf(node1, node2))
|
||||||
showConsensusFor(listOf(node1, node2, regulators[0]))
|
showConsensusFor(listOf(node1, node2, regulators[0]))
|
||||||
|
|
||||||
val instigator = Instigator(node2.info.legalIdentity, AutoOffer(notary.info.notaryIdentity, irs), node1.keyPair!!)
|
val instigator = Instigator(node2.info.legalIdentity, AutoOffer(notary.info.notaryIdentity, irs), node1.services.legalIdentityKey)
|
||||||
val instigatorTx: ListenableFuture<SignedTransaction> = node1.services.startFlow(instigator).resultFuture
|
val instigatorTx: ListenableFuture<SignedTransaction> = node1.services.startFlow(instigator).resultFuture
|
||||||
|
|
||||||
return Futures.allAsList(instigatorTx, acceptorTx).flatMap { instigatorTx }
|
return Futures.allAsList(instigatorTx, acceptorTx).flatMap { instigatorTx }
|
||||||
|
@ -2,7 +2,6 @@ package net.corda.simulation
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.crypto.generateKeyPair
|
|
||||||
import net.corda.core.flatMap
|
import net.corda.core.flatMap
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
@ -25,6 +24,7 @@ import net.corda.testing.node.TestClock
|
|||||||
import net.corda.testing.node.setTo
|
import net.corda.testing.node.setTo
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
|
import java.math.BigInteger
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
@ -50,8 +50,9 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
// This puts together a mock network of SimulatedNodes.
|
// This puts together a mock network of SimulatedNodes.
|
||||||
|
|
||||||
open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork, networkMapAddress: SingleMessageRecipient?,
|
open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork, networkMapAddress: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?)
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
: MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, keyPair) {
|
entropyRoot: BigInteger)
|
||||||
|
: MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
override fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
|
override fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
var counter = 0
|
var counter = 0
|
||||||
|
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
val letter = 'A' + counter
|
val letter = 'A' + counter
|
||||||
val city = bankLocations[counter++ % bankLocations.size]
|
val city = bankLocations[counter++ % bankLocations.size]
|
||||||
|
|
||||||
@ -69,12 +71,12 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
myLegalName = "Bank $letter",
|
myLegalName = "Bank $letter",
|
||||||
nearestCity = city,
|
nearestCity = city,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair)
|
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createAll(): List<SimulatedNode> {
|
fun createAll(): List<SimulatedNode> {
|
||||||
return bankLocations.map {
|
return bankLocations.map {
|
||||||
network.createNode(networkMap.info.address, start = false, nodeFactory = this, keyPair = generateKeyPair()) as SimulatedNode
|
network.createNode(networkMap.info.address, start = false, nodeFactory = this) as SimulatedNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,41 +84,44 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
val bankFactory = BankFactory()
|
val bankFactory = BankFactory()
|
||||||
|
|
||||||
object NetworkMapNodeFactory : MockNetwork.Factory {
|
object NetworkMapNodeFactory : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
networkMapAddr: SingleMessageRecipient?, advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
require(advertisedServices.containsType(NetworkMapService.type))
|
require(advertisedServices.containsType(NetworkMapService.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "Network coordination center",
|
myLegalName = "Network coordination center",
|
||||||
nearestCity = "Amsterdam",
|
nearestCity = "Amsterdam",
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {}
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object NotaryNodeFactory : MockNetwork.Factory {
|
object NotaryNodeFactory : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
require(advertisedServices.containsType(SimpleNotaryService.type))
|
require(advertisedServices.containsType(SimpleNotaryService.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "Notary Service",
|
myLegalName = "Notary Service",
|
||||||
nearestCity = "Zurich",
|
nearestCity = "Zurich",
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair)
|
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object RatesOracleFactory : MockNetwork.Factory {
|
object RatesOracleFactory : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
require(advertisedServices.containsType(NodeInterestRates.type))
|
require(advertisedServices.containsType(NodeInterestRates.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "Rates Service Provider",
|
myLegalName = "Rates Service Provider",
|
||||||
nearestCity = "Madrid",
|
nearestCity = "Madrid",
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
override fun start(): MockNetwork.MockNode {
|
override fun start(): MockNetwork.MockNode {
|
||||||
super.start()
|
super.start()
|
||||||
javaClass.classLoader.getResourceAsStream("example.rates.txt").use {
|
javaClass.classLoader.getResourceAsStream("example.rates.txt").use {
|
||||||
@ -132,13 +137,14 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
|
|
||||||
object RegulatorFactory : MockNetwork.Factory {
|
object RegulatorFactory : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "Regulator A",
|
myLegalName = "Regulator A",
|
||||||
nearestCity = "Paris",
|
nearestCity = "Paris",
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
|
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
|
||||||
// So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it.
|
// So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it.
|
||||||
// But that's fine for visualisation purposes.
|
// But that's fine for visualisation purposes.
|
||||||
|
@ -6,10 +6,12 @@ import com.google.common.util.concurrent.Futures
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.entropyToKeyPair
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.CordaPluginRegistry
|
import net.corda.core.node.CordaPluginRegistry
|
||||||
import net.corda.core.node.PhysicalLocation
|
import net.corda.core.node.PhysicalLocation
|
||||||
|
import net.corda.core.node.ServiceEntry
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
@ -28,6 +30,7 @@ import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
|||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
import java.math.BigInteger
|
||||||
import java.nio.file.FileSystem
|
import java.nio.file.FileSystem
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -72,14 +75,22 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
|
|
||||||
/** Allows customisation of how nodes are created. */
|
/** Allows customisation of how nodes are created. */
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
/**
|
||||||
|
* @param overrideServices a set of service entries to use in place of the node's default service entries,
|
||||||
|
* for example where a node's service is part of a cluster.
|
||||||
|
* @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value,
|
||||||
|
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
||||||
|
*/
|
||||||
fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNode
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
entropyRoot: BigInteger): MockNode
|
||||||
}
|
}
|
||||||
|
|
||||||
object DefaultFactory : Factory {
|
object DefaultFactory : Factory {
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, keyPair: KeyPair?): MockNode {
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
return MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair)
|
entropyRoot: BigInteger): MockNode {
|
||||||
|
return MockNode(config, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,12 +119,20 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param overrideServices a set of service entries to use in place of the node's default service entries,
|
||||||
|
* for example where a node's service is part of a cluster.
|
||||||
|
* @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value,
|
||||||
|
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
||||||
|
*/
|
||||||
open class MockNode(config: NodeConfiguration,
|
open class MockNode(config: NodeConfiguration,
|
||||||
val mockNet: MockNetwork,
|
val mockNet: MockNetwork,
|
||||||
override val networkMapAddress: SingleMessageRecipient?,
|
override val networkMapAddress: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>,
|
advertisedServices: Set<ServiceInfo>,
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val keyPair: KeyPair?) : AbstractNode(config, advertisedServices, TestClock(), mockNet.busyLatch) {
|
val overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
|
val entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue())) : AbstractNode(config, advertisedServices, TestClock(), mockNet.busyLatch) {
|
||||||
|
var counter = entropyRoot
|
||||||
override val log: Logger = loggerFor<MockNode>()
|
override val log: Logger = loggerFor<MockNode>()
|
||||||
override val serverThread: AffinityExecutor =
|
override val serverThread: AffinityExecutor =
|
||||||
if (mockNet.threadPerNode)
|
if (mockNet.threadPerNode)
|
||||||
@ -134,7 +153,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
|
|
||||||
override fun makeVaultService(): VaultService = NodeVaultService(services)
|
override fun makeVaultService(): VaultService = NodeVaultService(services)
|
||||||
|
|
||||||
override fun makeKeyManagementService(): KeyManagementService = E2ETestKeyManagementService(partyKeys)
|
override fun makeKeyManagementService(): KeyManagementService {
|
||||||
|
return E2ETestKeyManagementService(partyKeys + (overrideServices?.values ?: emptySet()))
|
||||||
|
}
|
||||||
|
|
||||||
override fun startMessagingService(rpcOps: RPCOps) {
|
override fun startMessagingService(rpcOps: RPCOps) {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
@ -144,7 +165,28 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
inNodeNetworkMapService = InMemoryNetworkMapService(services)
|
inNodeNetworkMapService = InMemoryNetworkMapService(services)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateKeyPair(): KeyPair = keyPair ?: super.generateKeyPair()
|
override fun makeServiceEntries(): List<ServiceEntry> {
|
||||||
|
val defaultEntries = super.makeServiceEntries()
|
||||||
|
return if (overrideServices == null) {
|
||||||
|
defaultEntries
|
||||||
|
} else {
|
||||||
|
defaultEntries.map {
|
||||||
|
val override = overrideServices[it.info]
|
||||||
|
if (override != null) {
|
||||||
|
// TODO: Store the key
|
||||||
|
ServiceEntry(it.info, Party(it.identity.name, override.public))
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not thread safe, but node construction is done on a single thread, so that should always be fine
|
||||||
|
override fun generateKeyPair(): KeyPair {
|
||||||
|
counter = counter.add(BigInteger.ONE)
|
||||||
|
return entropyToKeyPair(counter)
|
||||||
|
}
|
||||||
|
|
||||||
// It's OK to not have a network map service in the mock network.
|
// It's OK to not have a network map service in the mock network.
|
||||||
override fun noNetworkMapConfigured(): ListenableFuture<Unit> = Futures.immediateFuture(Unit)
|
override fun noNetworkMapConfigured(): ListenableFuture<Unit> = Futures.immediateFuture(Unit)
|
||||||
@ -189,9 +231,28 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
override fun acceptableLiveFiberCountOnStop(): Int = acceptableLiveFiberCountOnStop
|
override fun acceptableLiveFiberCountOnStop(): Int = acceptableLiveFiberCountOnStop
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a node, optionally created by the passed factory method. */
|
/**
|
||||||
|
* Returns a node, optionally created by the passed factory method.
|
||||||
|
* @param overrideServices a set of service entries to use in place of the node's default service entries,
|
||||||
|
* for example where a node's service is part of a cluster.
|
||||||
|
* @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value,
|
||||||
|
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
||||||
|
*/
|
||||||
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
||||||
start: Boolean = true, legalName: String? = null, keyPair: KeyPair? = null,
|
start: Boolean = true, legalName: String? = null, overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
||||||
|
vararg advertisedServices: ServiceInfo): MockNode
|
||||||
|
= createNode(networkMapAddress, forcedID, nodeFactory, start, legalName, overrideServices, BigInteger.valueOf(random63BitValue()), *advertisedServices)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a node, optionally created by the passed factory method.
|
||||||
|
* @param overrideServices a set of service entries to use in place of the node's default service entries,
|
||||||
|
* for example where a node's service is part of a cluster.
|
||||||
|
* @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value,
|
||||||
|
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
||||||
|
*/
|
||||||
|
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
||||||
|
start: Boolean = true, legalName: String? = null, overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
||||||
|
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
|
||||||
vararg advertisedServices: ServiceInfo): MockNode {
|
vararg advertisedServices: ServiceInfo): MockNode {
|
||||||
val newNode = forcedID == -1
|
val newNode = forcedID == -1
|
||||||
val id = if (newNode) nextNodeId++ else forcedID
|
val id = if (newNode) nextNodeId++ else forcedID
|
||||||
@ -205,7 +266,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
myLegalName = legalName ?: "Mock Company $id",
|
myLegalName = legalName ?: "Mock Company $id",
|
||||||
networkMapService = null,
|
networkMapService = null,
|
||||||
dataSourceProperties = makeTestDataSourceProperties("node_${id}_net_$networkId"))
|
dataSourceProperties = makeTestDataSourceProperties("node_${id}_net_$networkId"))
|
||||||
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair)
|
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, overrideServices, entropyRoot)
|
||||||
if (start) {
|
if (start) {
|
||||||
node.setup().start()
|
node.setup().start()
|
||||||
if (threadPerNode && networkMapAddress != null)
|
if (threadPerNode && networkMapAddress != null)
|
||||||
@ -242,8 +303,13 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
*/
|
*/
|
||||||
fun createTwoNodes(nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = null): Pair<MockNode, MockNode> {
|
fun createTwoNodes(nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = null): Pair<MockNode, MockNode> {
|
||||||
require(nodes.isEmpty())
|
require(nodes.isEmpty())
|
||||||
|
val notaryServiceInfo = ServiceInfo(SimpleNotaryService.type)
|
||||||
|
val notaryOverride = if (notaryKeyPair != null)
|
||||||
|
mapOf(Pair(notaryServiceInfo, notaryKeyPair))
|
||||||
|
else
|
||||||
|
null
|
||||||
return Pair(
|
return Pair(
|
||||||
createNode(null, -1, nodeFactory, true, null, notaryKeyPair, ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type)),
|
createNode(null, -1, nodeFactory, true, null, notaryOverride, BigInteger.valueOf(random63BitValue()), ServiceInfo(NetworkMapService.type), notaryServiceInfo),
|
||||||
createNode(nodes[0].info.address, -1, nodeFactory, true, null)
|
createNode(nodes[0].info.address, -1, nodeFactory, true, null)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -260,9 +326,14 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
*/
|
*/
|
||||||
fun createSomeNodes(numPartyNodes: Int = 2, nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = DUMMY_NOTARY_KEY): BasketOfNodes {
|
fun createSomeNodes(numPartyNodes: Int = 2, nodeFactory: Factory = defaultFactory, notaryKeyPair: KeyPair? = DUMMY_NOTARY_KEY): BasketOfNodes {
|
||||||
require(nodes.isEmpty())
|
require(nodes.isEmpty())
|
||||||
|
val notaryServiceInfo = ServiceInfo(SimpleNotaryService.type)
|
||||||
|
val notaryOverride = if (notaryKeyPair != null)
|
||||||
|
mapOf(Pair(notaryServiceInfo, notaryKeyPair))
|
||||||
|
else
|
||||||
|
null
|
||||||
val mapNode = createNode(null, nodeFactory = nodeFactory, advertisedServices = ServiceInfo(NetworkMapService.type))
|
val mapNode = createNode(null, nodeFactory = nodeFactory, advertisedServices = ServiceInfo(NetworkMapService.type))
|
||||||
val notaryNode = createNode(mapNode.info.address, nodeFactory = nodeFactory, keyPair = notaryKeyPair,
|
val notaryNode = createNode(mapNode.info.address, nodeFactory = nodeFactory, overrideServices = notaryOverride,
|
||||||
advertisedServices = ServiceInfo(SimpleNotaryService.type))
|
advertisedServices = notaryServiceInfo)
|
||||||
val nodes = ArrayList<MockNode>()
|
val nodes = ArrayList<MockNode>()
|
||||||
repeat(numPartyNodes) {
|
repeat(numPartyNodes) {
|
||||||
nodes += createPartyNode(mapNode.info.address)
|
nodes += createPartyNode(mapNode.info.address)
|
||||||
@ -270,12 +341,18 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
return BasketOfNodes(nodes, notaryNode, mapNode)
|
return BasketOfNodes(nodes, notaryNode, mapNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null, legalName: String? = null, keyPair: KeyPair? = null, serviceName: String? = null): MockNode {
|
fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null,
|
||||||
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, keyPair, ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName))
|
legalName: String? = null,
|
||||||
|
overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
||||||
|
serviceName: String? = null): MockNode {
|
||||||
|
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices, BigInteger.valueOf(random63BitValue()),
|
||||||
|
ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPartyNode(networkMapAddr: SingleMessageRecipient, legalName: String? = null, keyPair: KeyPair? = null): MockNode {
|
fun createPartyNode(networkMapAddr: SingleMessageRecipient,
|
||||||
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, keyPair)
|
legalName: String? = null,
|
||||||
|
overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNode {
|
||||||
|
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused") // This is used from the network visualiser tool.
|
@Suppress("unused") // This is used from the network visualiser tool.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user