Cleaned up NodeInfo API ()

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
client
jfx/src/integration-test/kotlin/net/corda/client/jfx
rpc/src/integration-test/kotlin/net/corda/client/rpc
core/src
main/kotlin/net/corda/core
test/java/net/corda/core/flows
docs/source/example-code/src/main/kotlin/net/corda/docs
node/src
integration-test/kotlin/net/corda/node/services
main/kotlin/net/corda/node
test/kotlin/net/corda/node/services
tools/explorer/src/main/kotlin/net/corda/explorer/views

View File

@ -132,9 +132,8 @@ class NodeMonitorModelTest : DriverBasedTest() {
@Test @Test
fun `cash issue and move`() { fun `cash issue and move`() {
val anonymous = false
val (_, issueIdentity) = rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow() 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 issueSmId: StateMachineRunId? = null
var moveSmId: StateMachineRunId? = null var moveSmId: StateMachineRunId? = null
@ -152,7 +151,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
require(remove.id == issueSmId) require(remove.id == issueSmId)
}, },
// MOVE - N.B. There are other framework flows that happen in parallel for the remote resolve transactions flow // 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 moveSmId = add.id
val initiator = add.stateMachineInfo.initiator val initiator = add.stateMachineInfo.initiator
require(initiator is FlowInitiator.RPC && initiator.username == "user1") require(initiator is FlowInitiator.RPC && initiator.username == "user1")
@ -167,7 +166,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
// MOVE // MOVE
expect { add: StateMachineUpdate.Added -> expect { add: StateMachineUpdate.Added ->
val initiator = add.stateMachineInfo.initiator 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.crypto.random63BitValue
import net.corda.core.flows.FlowInitiator 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.node.services.ServiceInfo
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
@ -105,7 +108,6 @@ class CordaRPCClientTest : NodeBasedTest() {
login(rpcUser.username, rpcUser.password) login(rpcUser.username, rpcUser.password)
connection!!.proxy.startFlow(::CashPaymentFlow, 100.DOLLARS, node.info.chooseIdentity()).use { connection!!.proxy.startFlow(::CashPaymentFlow, 100.DOLLARS, node.info.chooseIdentity()).use {
assertFalse(it is FlowProgressHandle<*>) assertFalse(it is FlowProgressHandle<*>)
assertTrue(it is FlowHandle<*>)
} }
} }

View File

@ -20,7 +20,7 @@ class BroadcastTransactionFlow(val notarisedTransaction: SignedTransaction,
@Suspendable @Suspendable
override fun call() { override fun call() {
// TODO: Messaging layer should handle this broadcast for us // 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. // SendTransactionFlow allows otherParty to access our data to resolve the transaction.
subFlow(SendTransactionFlow(participant, notarisedTransaction)) subFlow(SendTransactionFlow(participant, notarisedTransaction))
} }

View File

@ -2,8 +2,8 @@ package net.corda.core.flows
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.services.IdentityService import net.corda.core.node.services.IdentityService
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap 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 // Special case that if we're both parties, a single identity is generated
val identities = LinkedHashMap<Party, AnonymousParty>() val identities = LinkedHashMap<Party, AnonymousParty>()
if (otherSide in serviceHub.myInfo.legalIdentities) { if (serviceHub.myInfo.isLegalIdentity(otherSide)) {
identities.put(otherSide, legalIdentityAnonymous.party.anonymise()) identities.put(otherSide, legalIdentityAnonymous.party.anonymise())
} else { } else {
val anonymousOtherSide = sendAndReceive<PartyAndCertificate>(otherSide, legalIdentityAnonymous).unwrap { confidentialIdentity -> 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. * 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. // 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 @CordaSerializable
data class NodeInfo(val addresses: List<NetworkHostAndPort>, 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 legalIdentitiesAndCerts: List<PartyAndCertificate>,
val platformVersion: Int, val platformVersion: Int,
val advertisedServices: List<ServiceEntry> = emptyList(), 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. // TODO This part will be removed with services removal.
val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity.party 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> { fun serviceIdentities(type: ServiceType): List<Party> {
return advertisedServices.mapNotNull { if (it.info.type.isSubTypeOf(type)) it.identity.party else null } 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 com.google.common.primitives.Primitives;
import net.corda.core.identity.Party; import net.corda.core.identity.Party;
import net.corda.node.internal.StartedNode; import net.corda.node.internal.StartedNode;
import net.corda.testing.CoreTestUtils;
import net.corda.testing.node.MockNetwork; import net.corda.testing.node.MockNetwork;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -13,6 +12,7 @@ import org.junit.Test;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import static net.corda.testing.CoreTestUtils.chooseIdentity;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -40,7 +40,7 @@ public class FlowsInJavaTest {
@Test @Test
public void suspendableActionInsideUnwrap() throws Exception { public void suspendableActionInsideUnwrap() throws Exception {
node2.getInternals().registerInitiatedFlow(SendHelloAndThenReceive.class); 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(); mockNet.runNetwork();
assertThat(result.get()).isEqualTo("Hello"); assertThat(result.get()).isEqualTo("Hello");
} }
@ -55,7 +55,7 @@ public class FlowsInJavaTest {
} }
private void primitiveReceiveTypeTest(Class<?> receiveType) throws InterruptedException { 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(); Future<?> result = node1.getServices().startFlow(flow).getResultFuture();
mockNet.runNetwork(); mockNet.runNetwork();
try { try {

View File

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

View File

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

View File

@ -116,7 +116,7 @@ class SubmitTradeApprovalFlow(val tradeId: String,
// Notarise and distribute. // Notarise and distribute.
subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.chooseIdentity(), counterparty))) subFlow(FinalityFlow(signedTx, setOf(serviceHub.myInfo.chooseIdentity(), counterparty)))
// Return the initial state // 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}" "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. // 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" "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 // Check the context dependent parts of the transaction as the
// Contract verify method must not use serviceHub queries. // Contract verify method must not use serviceHub queries.
val state = ltx.outRef<TradeApprovalContract.State>(0) 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" "Proposal not one of our original proposals"
} }
require(state.state.data.counterparty == source) { require(state.state.data.counterparty == source) {

View File

@ -99,7 +99,7 @@ class BFTNotaryServiceTests {
val notary = bftNotaryCluster(clusterSize) val notary = bftNotaryCluster(clusterSize)
node.run { node.run {
val issueTx = signInitialTransaction(notary) { val issueTx = signInitialTransaction(notary) {
addOutputState(DummyContract.SingleOwnerState(owner = (info.chooseIdentity())), DUMMY_PROGRAM_ID) addOutputState(DummyContract.SingleOwnerState(owner = info.chooseIdentity()), DUMMY_PROGRAM_ID)
} }
database.transaction { database.transaction {
services.recordTransactions(issueTx) 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) val caCertificates: Array<X509Certificate> = listOf(legalIdentity.certificate, clientCa?.certificate?.cert)
.filterNotNull() .filterNotNull()
.toTypedArray() .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.partyNodes.forEach { it.legalIdentitiesAndCerts.forEach { service.verifyAndRegisterIdentity(it) } }
services.networkMapCache.changed.subscribe { mapChange -> services.networkMapCache.changed.subscribe { mapChange ->
// TODO how should we handle network map removal // 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? { override fun getPartyInfo(party: Party): PartyInfo? {
val nodes = serviceHub.database.transaction { queryByIdentityKey(party.owningKey) } 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) return PartyInfo.SingleNode(party, nodes[0].addresses)
} }
for (node in nodes) { 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.statemachine.StateMachineManager
import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.chooseIdentity import net.corda.testing.chooseIdentity
import net.corda.testing.contracts.DUMMY_PROGRAM_ID
import net.corda.testing.dummyCommand import net.corda.testing.dummyCommand
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.junit.After import org.junit.After
@ -81,7 +81,7 @@ class ScheduledFlowTests {
val state = serviceHub.toStateAndRef<ScheduledState>(stateRef) val state = serviceHub.toStateAndRef<ScheduledState>(stateRef)
val scheduledState = state.state.data val scheduledState = state.state.data
// Only run flow over states originating on this node // Only run flow over states originating on this node
if (scheduledState.source != serviceHub.myInfo.chooseIdentity()) { if (!serviceHub.myInfo.isLegalIdentity(scheduledState.source)) {
return return
} }
require(!scheduledState.processed) { "State should not have been previously processed" } require(!scheduledState.processed) { "State should not have been previously processed" }
@ -144,7 +144,7 @@ class ScheduledFlowTests {
fun `run a whole batch of scheduled flows`() { fun `run a whole batch of scheduled flows`() {
val N = 100 val N = 100
val futures = mutableListOf<CordaFuture<*>>() 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(nodeA.services.startFlow(InsertInitialStateFlow(nodeB.info.chooseIdentity())).resultFuture)
futures.add(nodeB.services.startFlow(InsertInitialStateFlow(nodeA.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.core.utilities.*
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.testing.ALICE import net.corda.testing.*
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.node.NodeBasedTest import net.corda.testing.node.NodeBasedTest
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 kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFails import kotlin.test.assertFails
import kotlin.test.assertTrue
class PersistentNetworkMapCacheTest : NodeBasedTest() { class PersistentNetworkMapCacheTest : NodeBasedTest() {
val partiesList = listOf(DUMMY_NOTARY, ALICE, BOB) 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`() { fun `restart node with DB map cache and no network map`() {
val alice = startNodesWithPort(listOf(ALICE), noNetworkMap = true)[0] val alice = startNodesWithPort(listOf(ALICE), noNetworkMap = true)[0]
val partyNodes = alice.services.networkMapCache.partyNodes 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(NullNetworkMapService, alice.inNodeNetworkMapService)
assertEquals(infos.size, partyNodes.size) assertEquals(infos.size, partyNodes.size)
assertEquals(infos.flatMap { it.legalIdentities }.toSet(), partyNodes.flatMap { it.legalIdentities }.toSet()) 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`() { fun `start 2 nodes without pointing at NetworkMapService and communicate with each other`() {
val parties = partiesList.subList(1, partiesList.size) val parties = partiesList.subList(1, partiesList.size)
val nodes = startNodesWithPort(parties, noNetworkMap = true) val nodes = startNodesWithPort(parties, noNetworkMap = true)
assert(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService }) assertTrue(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService })
assert(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } }) assertTrue(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } })
nodes.forEach { nodes.forEach {
val partyNodes = it.services.networkMapCache.partyNodes val partyNodes = it.services.networkMapCache.partyNodes
assertEquals(infos.size, partyNodes.size) 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`() { fun `start 2 nodes pointing at NetworkMapService but don't start network map node`() {
val parties = partiesList.subList(1, partiesList.size) val parties = partiesList.subList(1, partiesList.size)
val nodes = startNodesWithPort(parties, noNetworkMap = false) val nodes = startNodesWithPort(parties, noNetworkMap = false)
assert(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService }) assertTrue(nodes.all { it.inNodeNetworkMapService == NullNetworkMapService })
assert(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } }) assertTrue(nodes.all { NetworkMapService.type !in it.info.advertisedServices.map { it.info.type } })
nodes.forEach { nodes.forEach {
val partyNodes = it.services.networkMapCache.partyNodes val partyNodes = it.services.networkMapCache.partyNodes
assertEquals(infos.size, partyNodes.size) 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. // Start 2 nodes pointing at network map, but don't start network map service.
val otherNodes = startNodesWithPort(parties, noNetworkMap = false) val otherNodes = startNodesWithPort(parties, noNetworkMap = false)
otherNodes.forEach { node -> 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. // 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] val charlie = startNodesWithPort(listOf(CHARLIE), noNetworkMap = false)[0]
otherNodes.forEach { 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. // Start Network Map and see that charlie node appears in caches.
val nms = startNodesWithPort(listOf(DUMMY_NOTARY), noNetworkMap = false)[0] val nms = startNodesWithPort(listOf(DUMMY_NOTARY), noNetworkMap = false)[0]
nms.internals.startupComplete.get() nms.internals.startupComplete.get()
assert(nms.inNodeNetworkMapService != NullNetworkMapService) assertTrue(nms.inNodeNetworkMapService != NullNetworkMapService)
assert(infos.any { it.legalIdentities.toSet() == nms.info.legalIdentities.toSet() }) assertTrue(infos.any { it.legalIdentities.toSet() == nms.info.legalIdentities.toSet() })
otherNodes.forEach { 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. charlie.internals.nodeReadyFuture.get() // Finish registration.
checkConnectivity(listOf(otherNodes[0], nms)) // Checks connectivity from A to NMS. 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 cacheB = otherNodes[1].services.networkMapCache.partyNodes
val cacheC = charlie.services.networkMapCache.partyNodes val cacheC = charlie.services.networkMapCache.partyNodes
assertEquals(4, cacheC.size) // Charlie fetched data from NetworkMap 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(), cacheB.toSet())
assertEquals(cacheA.toSet(), cacheC.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.client.jfx.utils.*
import net.corda.core.contracts.ContractState import net.corda.core.contracts.ContractState
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.CityDatabase
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.ScreenCoordinate import net.corda.core.node.ScreenCoordinate
import net.corda.core.node.WorldMapLocation
import net.corda.core.utilities.toBase58String import net.corda.core.utilities.toBase58String
import net.corda.explorer.formatters.PartyNameFormatter import net.corda.explorer.formatters.PartyNameFormatter
import net.corda.explorer.model.CordaView import net.corda.explorer.model.CordaView
@ -39,10 +41,10 @@ class Network : CordaView() {
override val root by fxml<Parent>() override val root by fxml<Parent>()
override val icon = FontAwesomeIcon.GLOBE override val icon = FontAwesomeIcon.GLOBE
// Inject data. // Inject data.
val myIdentity by observableValue(NetworkIdentityModel::myIdentity) private val myIdentity by observableValue(NetworkIdentityModel::myIdentity)
val notaries by observableList(NetworkIdentityModel::notaries) private val notaries by observableList(NetworkIdentityModel::notaries)
val peers by observableList(NetworkIdentityModel::parties) private val peers by observableList(NetworkIdentityModel::parties)
val transactions by observableList(TransactionDataModel::partiallyResolvedTransactions) private val transactions by observableList(TransactionDataModel::partiallyResolvedTransactions)
var centralPeer: String? = null var centralPeer: String? = null
private var centralLabel: ObservableValue<Label?> 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 List<ContractState>.getParties() = map { it.participants.map { it.owningKey.toKnownParty() } }.flatten()
private fun fireBulletBetweenNodes(senderParty: Party, destParty: Party, startType: String, endType: String) { private fun fireBulletBetweenNodes(senderParty: Party, destParty: Party, startType: String, endType: String) {
val senderNode = allComponents.firstOrNull { senderParty in it.nodeInfo.legalIdentities } ?: return val senderNode = allComponents.firstOrNull { it.nodeInfo.isLegalIdentity(senderParty) } ?: return
val destNode = allComponents.firstOrNull { destParty in it.nodeInfo.legalIdentities } ?: 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 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 receiver = destNode.label.boundsInParentProperty().map { Point2D(it.width / 2 + it.minX, it.height / 4 - 2.5 + it.minY) }
val bullet = Circle(3.0) val bullet = Circle(3.0)
@ -254,4 +256,8 @@ class Network : CordaView() {
mapPane.children.add(1, line) mapPane.children.add(1, line)
mapPane.children.add(bullet) mapPane.children.add(bullet)
} }
private fun NodeInfo.getWorldMapLocation(): WorldMapLocation? {
return CityDatabase[legalIdentitiesAndCerts[0].name.locality]
}
} }