Cleaned up NodeInfo API (#1535)

This commit is contained in:
Shams Asari 2017-09-18 13:09:29 +01:00 committed by josecoll
parent 2c5aa4eead
commit 4c40c764c3
15 changed files with 65 additions and 64 deletions

View File

@ -132,9 +132,8 @@ class NodeMonitorModelTest : DriverBasedTest() {
@Test
fun `cash issue and move`() {
val anonymous = false
val (_, issueIdentity) = rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow()
val (_, paymentIdentity) = rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, bobNode.chooseIdentity()).returnValue.getOrThrow()
rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, bobNode.chooseIdentity()).returnValue.getOrThrow()
var issueSmId: StateMachineRunId? = null
var moveSmId: StateMachineRunId? = null
@ -152,7 +151,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
require(remove.id == issueSmId)
},
// MOVE - N.B. There are other framework flows that happen in parallel for the remote resolve transactions flow
expect(match = { it is StateMachineUpdate.Added && it.stateMachineInfo.flowLogicClassName == CashPaymentFlow::class.java.name }) { add: StateMachineUpdate.Added ->
expect(match = { it.stateMachineInfo.flowLogicClassName == CashPaymentFlow::class.java.name }) { add: StateMachineUpdate.Added ->
moveSmId = add.id
val initiator = add.stateMachineInfo.initiator
require(initiator is FlowInitiator.RPC && initiator.username == "user1")
@ -167,7 +166,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
// MOVE
expect { add: StateMachineUpdate.Added ->
val initiator = add.stateMachineInfo.initiator
require(initiator is FlowInitiator.Peer && initiator.party.name == aliceNode.chooseIdentity().name)
require(initiator is FlowInitiator.Peer && aliceNode.isLegalIdentity(initiator.party))
}
)
}

View File

@ -2,7 +2,10 @@ package net.corda.client.rpc
import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowInitiator
import net.corda.core.messaging.*
import net.corda.core.messaging.FlowProgressHandle
import net.corda.core.messaging.StateMachineUpdate
import net.corda.core.messaging.startFlow
import net.corda.core.messaging.startTrackedFlow
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
@ -105,7 +108,6 @@ class CordaRPCClientTest : NodeBasedTest() {
login(rpcUser.username, rpcUser.password)
connection!!.proxy.startFlow(::CashPaymentFlow, 100.DOLLARS, node.info.chooseIdentity()).use {
assertFalse(it is FlowProgressHandle<*>)
assertTrue(it is FlowHandle<*>)
}
}

View File

@ -20,7 +20,7 @@ class BroadcastTransactionFlow(val notarisedTransaction: SignedTransaction,
@Suspendable
override fun call() {
// TODO: Messaging layer should handle this broadcast for us
participants.filter { it !in serviceHub.myInfo.legalIdentities }.forEach { participant ->
participants.filter { !serviceHub.myInfo.isLegalIdentity(it) }.forEach { participant ->
// SendTransactionFlow allows otherParty to access our data to resolve the transaction.
subFlow(SendTransactionFlow(participant, notarisedTransaction))
}

View File

@ -2,8 +2,8 @@ package net.corda.core.flows
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
@ -40,7 +40,7 @@ class SwapIdentitiesFlow(val otherSide: Party,
// Special case that if we're both parties, a single identity is generated
val identities = LinkedHashMap<Party, AnonymousParty>()
if (otherSide in serviceHub.myInfo.legalIdentities) {
if (serviceHub.myInfo.isLegalIdentity(otherSide)) {
identities.put(otherSide, legalIdentityAnonymous.party.anonymise())
} else {
val anonymousOtherSide = sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity ->

View File

@ -18,10 +18,9 @@ data class ServiceEntry(val info: ServiceInfo, val identity: PartyAndCertificate
* Info about a network node that acts on behalf of some form of contract party.
*/
// TODO We currently don't support multi-IP/multi-identity nodes, we only left slots in the data structures.
// Note that order of `legalIdentitiesAndCerts` is now important. We still treat the first identity as a special one.
// It will change after introducing proper multi-identity management.
@CordaSerializable
data class NodeInfo(val addresses: List<NetworkHostAndPort>,
/** Non-empty list of all the identities, plus certificates, that belong to this node. */
val legalIdentitiesAndCerts: List<PartyAndCertificate>,
val platformVersion: Int,
val advertisedServices: List<ServiceEntry> = emptyList(),
@ -33,17 +32,16 @@ data class NodeInfo(val addresses: List<NetworkHostAndPort>,
// TODO This part will be removed with services removal.
val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity.party
@Transient private var _legalIdentities: List<Party>? = null
val legalIdentities: List<Party> get() {
return _legalIdentities ?: legalIdentitiesAndCerts.map { it.party }.also { _legalIdentities = it }
}
/** Returns true iff [party] is one of the identities of this node. */
fun isLegalIdentity(party: Party): Boolean = party in legalIdentities
fun serviceIdentities(type: ServiceType): List<Party> {
return advertisedServices.mapNotNull { if (it.info.type.isSubTypeOf(type)) it.identity.party else null }
}
/**
* Uses node's owner X500 name to infer the node's location. Used in Explorer in map view.
*/
fun getWorldMapLocation(): WorldMapLocation? {
val nodeOwnerLocation = legalIdentitiesAndCerts.first().name.locality
return nodeOwnerLocation.let { CityDatabase[it] }
}
val legalIdentities: List<Party>
get() = legalIdentitiesAndCerts.map { it.party }
}

View File

@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable;
import com.google.common.primitives.Primitives;
import net.corda.core.identity.Party;
import net.corda.node.internal.StartedNode;
import net.corda.testing.CoreTestUtils;
import net.corda.testing.node.MockNetwork;
import org.junit.After;
import org.junit.Before;
@ -13,6 +12,7 @@ import org.junit.Test;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static net.corda.testing.CoreTestUtils.chooseIdentity;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.fail;
@ -40,7 +40,7 @@ public class FlowsInJavaTest {
@Test
public void suspendableActionInsideUnwrap() throws Exception {
node2.getInternals().registerInitiatedFlow(SendHelloAndThenReceive.class);
Future<String> result = node1.getServices().startFlow(new SendInUnwrapFlow(CoreTestUtils.chooseIdentity(node2.getInfo()))).getResultFuture();
Future<String> result = node1.getServices().startFlow(new SendInUnwrapFlow(chooseIdentity(node2.getInfo()))).getResultFuture();
mockNet.runNetwork();
assertThat(result.get()).isEqualTo("Hello");
}
@ -55,7 +55,7 @@ public class FlowsInJavaTest {
}
private void primitiveReceiveTypeTest(Class<?> receiveType) throws InterruptedException {
PrimitiveReceiveFlow flow = new PrimitiveReceiveFlow(CoreTestUtils.chooseIdentity(node2.getInfo()), receiveType);
PrimitiveReceiveFlow flow = new PrimitiveReceiveFlow(chooseIdentity(node2.getInfo()), receiveType);
Future<?> result = node1.getServices().startFlow(flow).getResultFuture();
mockNet.runNetwork();
try {

View File

@ -20,7 +20,6 @@ import net.corda.finance.flows.AbstractCashFlow
import net.corda.finance.flows.CashException
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.testing.chooseIdentity
import java.util.*
// DOCSTART CustomVaultQuery
@ -140,7 +139,7 @@ object TopupIssuerFlow {
val issueTx = subFlow(issueCashFlow)
// NOTE: issueCashFlow performs a Broadcast (which stores a local copy of the txn to the ledger)
// short-circuit when issuing to self
if (issueTo == serviceHub.myInfo.chooseIdentity())
if (serviceHub.myInfo.isLegalIdentity(issueTo))
return issueTx
// now invoke Cash subflow to Move issued assetType to issue requester
progressTracker.currentStep = TRANSFERRING

View File

@ -47,7 +47,7 @@ private fun gatherOurInputs(serviceHub: ServiceHub,
val fullCriteria = fungibleCriteria.and(vaultCriteria).and(cashCriteria)
val eligibleStates = serviceHub.vaultService.tryLockFungibleStatesForSpending<Cash.State, Currency>(lockId, fullCriteria, amountRequired.withoutIssuer(), Cash.State::class.java)
val eligibleStates = serviceHub.vaultService.tryLockFungibleStatesForSpending(lockId, fullCriteria, amountRequired.withoutIssuer(), Cash.State::class.java)
check(eligibleStates.isNotEmpty()) { "Insufficient funds" }
val amount = eligibleStates.fold(0L) { tot, x -> tot + x.state.data.amount.quantity }
@ -97,11 +97,11 @@ class ForeignExchangeFlow(val tradeId: String,
// Select correct sides of the Fx exchange to query for.
// Specifically we own the assets we wish to sell.
// Also prepare the other side query
val (localRequest, remoteRequest) = if (baseCurrencySeller == serviceHub.myInfo.chooseIdentity()) {
val (localRequest, remoteRequest) = if (serviceHub.myInfo.isLegalIdentity(baseCurrencySeller)) {
val local = FxRequest(tradeId, baseCurrencyAmount, baseCurrencySeller, baseCurrencyBuyer)
val remote = FxRequest(tradeId, quoteCurrencyAmount, baseCurrencyBuyer, baseCurrencySeller)
Pair(local, remote)
} else if (baseCurrencyBuyer == serviceHub.myInfo.chooseIdentity()) {
} else if (serviceHub.myInfo.isLegalIdentity(baseCurrencyBuyer)) {
val local = FxRequest(tradeId, quoteCurrencyAmount, baseCurrencyBuyer, baseCurrencySeller)
val remote = FxRequest(tradeId, baseCurrencyAmount, baseCurrencySeller, baseCurrencyBuyer)
Pair(local, remote)
@ -133,8 +133,8 @@ class ForeignExchangeFlow(val tradeId: String,
>= remoteRequestWithNotary.amount.quantity) {
"the provided inputs don't provide sufficient funds"
}
require(it.filter { it.owner == serviceHub.myInfo.chooseIdentity() }.
map { it.amount.quantity }.sum() == remoteRequestWithNotary.amount.quantity) {
val sum = it.filter { it.owner.let { it is Party && serviceHub.myInfo.isLegalIdentity(it) } }.map { it.amount.quantity }.sum()
require(sum == remoteRequestWithNotary.amount.quantity) {
"the provided outputs don't provide the request quantity"
}
it // return validated response
@ -195,7 +195,7 @@ class ForeignExchangeFlow(val tradeId: String,
}
@InitiatedBy(ForeignExchangeFlow::class)
class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic<Unit>() {
class ForeignExchangeRemoteFlow(private val source: Party) : FlowLogic<Unit>() {
@Suspendable
override fun call() {
// Initial receive from remote party
@ -206,7 +206,7 @@ class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic<Unit>() {
// the lifecycle of the Fx trades which would be included in the transaction
// Check request is for us
require(serviceHub.myInfo.chooseIdentity() == it.owner) {
require(serviceHub.myInfo.isLegalIdentity(it.owner)) {
"Request does not include the correct counterparty"
}
require(source == it.counterparty) {

View File

@ -116,7 +116,7 @@ class SubmitTradeApprovalFlow(val tradeId: String,
// Notarise and distribute.
subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.chooseIdentity(), counterparty)))
// Return the initial state
return signedTx.tx.outRef<TradeApprovalContract.State>(0)
return signedTx.tx.outRef(0)
}
}
@ -149,7 +149,7 @@ class SubmitCompletionFlow(val ref: StateRef, val verdict: WorkflowState) : Flow
"Input trade not modifiable ${latestRecord.state.data.state}"
}
// Check we are the correct Party to run the protocol. Note they will counter check this too.
require(latestRecord.state.data.counterparty == serviceHub.myInfo.chooseIdentity()) {
require(serviceHub.myInfo.isLegalIdentity(latestRecord.state.data.counterparty)) {
"The counterparty must give the verdict"
}
@ -225,7 +225,7 @@ class RecordCompletionFlow(val source: Party) : FlowLogic<Unit>() {
// Check the context dependent parts of the transaction as the
// Contract verify method must not use serviceHub queries.
val state = ltx.outRef<TradeApprovalContract.State>(0)
require(state.state.data.source == serviceHub.myInfo.chooseIdentity()) {
require(serviceHub.myInfo.isLegalIdentity(state.state.data.source)) {
"Proposal not one of our original proposals"
}
require(state.state.data.counterparty == source) {

View File

@ -99,7 +99,7 @@ class BFTNotaryServiceTests {
val notary = bftNotaryCluster(clusterSize)
node.run {
val issueTx = signInitialTransaction(notary) {
addOutputState(DummyContract.SingleOwnerState(owner = (info.chooseIdentity())), DUMMY_PROGRAM_ID)
addOutputState(DummyContract.SingleOwnerState(owner = info.chooseIdentity()), DUMMY_PROGRAM_ID)
}
database.transaction {
services.recordTransactions(issueTx)

View File

@ -579,7 +579,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
val caCertificates: Array<X509Certificate> = listOf(legalIdentity.certificate, clientCa?.certificate?.cert)
.filterNotNull()
.toTypedArray()
val service = PersistentIdentityService(info.legalIdentitiesAndCerts.toSet(), trustRoot = trustRoot, caCertificates = *caCertificates)
val service = PersistentIdentityService(info.legalIdentitiesAndCerts, trustRoot = trustRoot, caCertificates = *caCertificates)
services.networkMapCache.partyNodes.forEach { it.legalIdentitiesAndCerts.forEach { service.verifyAndRegisterIdentity(it) } }
services.networkMapCache.changed.subscribe { mapChange ->
// TODO how should we handle network map removal

View File

@ -76,7 +76,7 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal)
override fun getPartyInfo(party: Party): PartyInfo? {
val nodes = serviceHub.database.transaction { queryByIdentityKey(party.owningKey) }
if (nodes.size == 1 && party in nodes[0].legalIdentities) {
if (nodes.size == 1 && nodes[0].isLegalIdentity(party)) {
return PartyInfo.SingleNode(party, nodes[0].addresses)
}
for (node in nodes) {

View File

@ -21,8 +21,8 @@ import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.chooseIdentity
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.dummyCommand
import net.corda.testing.node.MockNetwork
import org.junit.After
@ -81,7 +81,7 @@ class ScheduledFlowTests {
val state = serviceHub.toStateAndRef<ScheduledState>(stateRef)
val scheduledState = state.state.data
// Only run flow over states originating on this node
if (scheduledState.source != serviceHub.myInfo.chooseIdentity()) {
if (!serviceHub.myInfo.isLegalIdentity(scheduledState.source)) {
return
}
require(!scheduledState.processed) { "State should not have been previously processed" }
@ -144,7 +144,7 @@ class ScheduledFlowTests {
fun `run a whole batch of scheduled flows`() {
val N = 100
val futures = mutableListOf<CordaFuture<*>>()
for (i in 0..N - 1) {
for (i in 0 until N) {
futures.add(nodeA.services.startFlow(InsertInitialStateFlow(nodeB.info.chooseIdentity())).resultFuture)
futures.add(nodeB.services.startFlow(InsertInitialStateFlow(nodeA.info.chooseIdentity())).resultFuture)
}

View File

@ -10,17 +10,14 @@ import net.corda.core.node.NodeInfo
import net.corda.core.utilities.*
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.CHARLIE
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.node.NodeBasedTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFails
import kotlin.test.assertTrue
class PersistentNetworkMapCacheTest : NodeBasedTest() {
val partiesList = listOf(DUMMY_NOTARY, ALICE, BOB)
@ -64,7 +61,7 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
fun `restart node with DB map cache and no network map`() {
val alice = startNodesWithPort(listOf(ALICE), noNetworkMap = true)[0]
val partyNodes = alice.services.networkMapCache.partyNodes
assert(NetworkMapService.type !in alice.info.advertisedServices.map { it.info.type })
assertTrue(NetworkMapService.type !in alice.info.advertisedServices.map { it.info.type })
assertEquals(NullNetworkMapService, alice.inNodeNetworkMapService)
assertEquals(infos.size, partyNodes.size)
assertEquals(infos.flatMap { it.legalIdentities }.toSet(), partyNodes.flatMap { it.legalIdentities }.toSet())
@ -74,8 +71,8 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
fun `start 2 nodes without pointing at NetworkMapService and communicate with each other`() {
val parties = partiesList.subList(1, partiesList.size)
val nodes = startNodesWithPort(parties, noNetworkMap = true)
assert(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService })
assert(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } })
assertTrue(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService })
assertTrue(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } })
nodes.forEach {
val partyNodes = it.services.networkMapCache.partyNodes
assertEquals(infos.size, partyNodes.size)
@ -88,8 +85,8 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
fun `start 2 nodes pointing at NetworkMapService but don't start network map node`() {
val parties = partiesList.subList(1, partiesList.size)
val nodes = startNodesWithPort(parties, noNetworkMap = false)
assert(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService })
assert(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } })
assertTrue(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService })
assertTrue(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } })
nodes.forEach {
val partyNodes = it.services.networkMapCache.partyNodes
assertEquals(infos.size, partyNodes.size)
@ -116,20 +113,20 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
// Start 2 nodes pointing at network map, but don't start network map service.
val otherNodes = startNodesWithPort(parties, noNetworkMap = false)
otherNodes.forEach { node ->
assert(infos.any { it.legalIdentitiesAndCerts.toSet() == node.info.legalIdentitiesAndCerts.toSet() })
assertTrue(infos.any { it.legalIdentitiesAndCerts.toSet() == node.info.legalIdentitiesAndCerts.toSet() })
}
// Start node that is not in databases of other nodes. Point to NMS. Which has't started yet.
val charlie = startNodesWithPort(listOf(CHARLIE), noNetworkMap = false)[0]
otherNodes.forEach {
assert(charlie.info.chooseIdentity() !in it.services.networkMapCache.partyNodes.flatMap { it.legalIdentities })
assertThat(it.services.networkMapCache.partyNodes).doesNotContain(charlie.info)
}
// Start Network Map and see that charlie node appears in caches.
val nms = startNodesWithPort(listOf(DUMMY_NOTARY), noNetworkMap = false)[0]
nms.internals.startupComplete.get()
assert(nms.inNodeNetworkMapService != NullNetworkMapService)
assert(infos.any { it.legalIdentities.toSet() == nms.info.legalIdentities.toSet() })
assertTrue(nms.inNodeNetworkMapService != NullNetworkMapService)
assertTrue(infos.any { it.legalIdentities.toSet() == nms.info.legalIdentities.toSet() })
otherNodes.forEach {
assert(nms.info.chooseIdentity() in it.services.networkMapCache.partyNodes.map { it.chooseIdentity() })
assertTrue(nms.info.chooseIdentity() in it.services.networkMapCache.partyNodes.map { it.chooseIdentity() })
}
charlie.internals.nodeReadyFuture.get() // Finish registration.
checkConnectivity(listOf(otherNodes[0], nms)) // Checks connectivity from A to NMS.
@ -137,7 +134,7 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
val cacheB = otherNodes[1].services.networkMapCache.partyNodes
val cacheC = charlie.services.networkMapCache.partyNodes
assertEquals(4, cacheC.size) // Charlie fetched data from NetworkMap
assert(charlie.info.chooseIdentity() in cacheB.map { it.chooseIdentity() }) // Other nodes also fetched data from Network Map with node C.
assertThat(cacheB).contains(charlie.info)
assertEquals(cacheA.toSet(), cacheB.toSet())
assertEquals(cacheA.toSet(), cacheC.toSet())
}

View File

@ -28,8 +28,10 @@ import net.corda.client.jfx.model.*
import net.corda.client.jfx.utils.*
import net.corda.core.contracts.ContractState
import net.corda.core.identity.Party
import net.corda.core.node.CityDatabase
import net.corda.core.node.NodeInfo
import net.corda.core.node.ScreenCoordinate
import net.corda.core.node.WorldMapLocation
import net.corda.core.utilities.toBase58String
import net.corda.explorer.formatters.PartyNameFormatter
import net.corda.explorer.model.CordaView
@ -39,10 +41,10 @@ class Network : CordaView() {
override val root by fxml<Parent>()
override val icon = FontAwesomeIcon.GLOBE
// Inject data.
val myIdentity by observableValue(NetworkIdentityModel::myIdentity)
val notaries by observableList(NetworkIdentityModel::notaries)
val peers by observableList(NetworkIdentityModel::parties)
val transactions by observableList(TransactionDataModel::partiallyResolvedTransactions)
private val myIdentity by observableValue(NetworkIdentityModel::myIdentity)
private val notaries by observableList(NetworkIdentityModel::notaries)
private val peers by observableList(NetworkIdentityModel::parties)
private val transactions by observableList(TransactionDataModel::partiallyResolvedTransactions)
var centralPeer: String? = null
private var centralLabel: ObservableValue<Label?>
@ -215,8 +217,8 @@ class Network : CordaView() {
private fun List<ContractState>.getParties() = map { it.participants.map { it.owningKey.toKnownParty() } }.flatten()
private fun fireBulletBetweenNodes(senderParty: Party, destParty: Party, startType: String, endType: String) {
val senderNode = allComponents.firstOrNull { senderParty in it.nodeInfo.legalIdentities } ?: return
val destNode = allComponents.firstOrNull { destParty in it.nodeInfo.legalIdentities } ?: return
val senderNode = allComponents.firstOrNull { it.nodeInfo.isLegalIdentity(senderParty) } ?: return
val destNode = allComponents.firstOrNull { it.nodeInfo.isLegalIdentity(destParty) } ?: return
val sender = senderNode.label.boundsInParentProperty().map { Point2D(it.width / 2 + it.minX, it.height / 4 - 2.5 + it.minY) }
val receiver = destNode.label.boundsInParentProperty().map { Point2D(it.width / 2 + it.minX, it.height / 4 - 2.5 + it.minY) }
val bullet = Circle(3.0)
@ -254,4 +256,8 @@ class Network : CordaView() {
mapPane.children.add(1, line)
mapPane.children.add(bullet)
}
private fun NodeInfo.getWorldMapLocation(): WorldMapLocation? {
return CityDatabase[legalIdentitiesAndCerts[0].name.locality]
}
}