Change ServiceType to a sealed class from an abstract class

Allow AdvertisedServices to have their own identity and keys. Also, rationalise legalIdentity onto the local node's NodeInfo which is available on ServiceHub

Fixup after rebase

Remove legal identity that was on storage service. Now access via myInfo.legalIdentity and key via keyManagement lookup.

Enforce singleton notary per node for now

Tidy up based upon Rick's suggestions

Handle PR comments

clean up imports

Fix typo

Fixup rename

Capitalise comment

Eliminate unused variable warning

Make changes based upon PR comments

Cleanup whitespace changes
This commit is contained in:
Matthew Nesbit
2016-10-04 14:04:52 +01:00
parent 4e2f0e0ff9
commit 1e836edd78
64 changed files with 463 additions and 325 deletions

View File

@ -16,7 +16,7 @@ class DriverTests {
// Check that the node is registered in the network map
poll("network map cache for $nodeName") {
networkMapCache.get().firstOrNull {
it.identity.name == nodeName
it.legalIdentity.name == nodeName
}
}
// Check that the port is bound
@ -33,8 +33,8 @@ class DriverTests {
@Test
fun simpleNodeStartupShutdownWorks() {
val (notary, regulator) = driver {
val notary = startNode("TestNotary", setOf(ServiceInfo(SimpleNotaryService.Type)))
val regulator = startNode("Regulator", setOf(ServiceInfo(RegulatorService.Type)))
val notary = startNode("TestNotary", setOf(ServiceInfo(SimpleNotaryService.type)))
val regulator = startNode("Regulator", setOf(ServiceInfo(RegulatorService.type)))
nodeMustBeUp(networkMapCache, notary.get(), "TestNotary")
nodeMustBeUp(networkMapCache, regulator.get(), "Regulator")

View File

@ -77,7 +77,7 @@ fun DriverDSLExposedInterface.startClient(localServer: ArtemisMessagingServer) =
fun DriverDSLExposedInterface.startClient(remoteNodeInfo: NodeInfo, providedName: String? = null) =
startClient(
providedName = providedName ?: "${remoteNodeInfo.identity.name}-client",
providedName = providedName ?: "${remoteNodeInfo.legalIdentity.name}-client",
serverAddress = ArtemisMessagingComponent.toHostAndPort(remoteNodeInfo.address)
)
@ -309,7 +309,7 @@ class DriverDSL(
registerProcess(DriverDSL.startNode(config, quasarJarPath, debugPort))
poll("network map cache for $name") {
networkMapCache.partyNodes.forEach {
if (it.identity.name == name) {
if (it.legalIdentity.name == name) {
return@poll it
}
}
@ -383,7 +383,7 @@ class DriverDSL(
networkMapCache.addMapService(networkMapClient, networkMapAddr, true)
networkMapNodeInfo = poll("network map cache for $networkMapName") {
networkMapCache.partyNodes.forEach {
if (it.identity.name == networkMapName) {
if (it.legalIdentity.name == networkMapName) {
return@poll it
}
}

View File

@ -8,10 +8,7 @@ import com.r3corda.core.RunOnCallerThread
import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.X509Utilities
import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.CityDatabase
import com.r3corda.core.node.CordaPluginRegistry
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.PhysicalLocation
import com.r3corda.core.node.*
import com.r3corda.core.node.services.*
import com.r3corda.core.node.services.NetworkMapCache.MapChangeType
import com.r3corda.core.protocols.ProtocolLogic
@ -96,6 +93,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
val servicesThatAcceptUploads: List<AcceptsFileUpload> = _servicesThatAcceptUploads
private val protocolFactories = ConcurrentHashMap<Class<*>, (Party) -> ProtocolLogic<*>>()
protected val partyKeys = mutableSetOf<KeyPair>()
val services = object : ServiceHubInternal() {
override val networkService: MessagingServiceInternal get() = net
@ -106,6 +104,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
override val identityService: IdentityService get() = identity
override val schedulerService: SchedulerService get() = scheduler
override val clock: Clock = platformClock
override val myInfo: NodeInfo get() = info
override val schemaService: SchemaService get() = schemas
// Internal only
@ -130,7 +129,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
}
val info: NodeInfo by lazy {
NodeInfo(net.myAddress, storage.myLegalIdentity, advertisedServices, findMyLocation())
val services = mutableListOf<ServiceEntry>()
for (service in advertisedServices) {
val identity = obtainKeyPair(configuration.basedir, service.type.id + "-private-key", service.type.id + "-public", service.type.id).first
services += ServiceEntry(service, identity)
}
val legalIdentity = obtainLegalIdentity()
NodeInfo(net.myAddress, legalIdentity, services, findMyLocation())
}
open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
@ -214,7 +219,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
// TODO: uniquenessProvider creation should be inside makeNotaryService(), but notary service initialisation
// depends on smm, while smm depends on tokenizableServices, which uniquenessProvider is part of
advertisedServices.singleOrNull { it.type.isSubTypeOf(NotaryService.Type) }?.let {
advertisedServices.singleOrNull { it.type.isNotary() }?.let {
uniquenessProvider = makeUniquenessProvider()
tokenizableServices.add(uniquenessProvider!!)
}
@ -321,10 +326,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
}
private fun buildAdvertisedServices() {
val serviceTypes = info.advertisedServices.map { it.type }
if (NetworkMapService.Type in serviceTypes) makeNetworkMapService()
val serviceTypes = info.advertisedServices.map { it.info.type }
if (NetworkMapService.type in serviceTypes) makeNetworkMapService()
val notaryServiceType = serviceTypes.singleOrNull { it.isSubTypeOf(NotaryService.Type) }
val notaryServiceType = serviceTypes.singleOrNull { it.isNotary() }
if (notaryServiceType != null) {
inNodeNotaryService = makeNotaryService(notaryServiceType)
}
@ -335,7 +340,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
* updates) if one has been supplied.
*/
private fun registerWithNetworkMap(): ListenableFuture<Unit> {
require(networkMapService != null || NetworkMapService.Type in advertisedServices.map { it.type }) {
require(networkMapService != null || NetworkMapService.type in advertisedServices.map { it.type }) {
"Initial network map address must indicate a node that provides a network map service"
}
services.networkMapCache.addNode(info)
@ -365,11 +370,12 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
val instant = platformClock.instant()
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
val reg = NodeRegistration(info, instant.toEpochMilli(), type, expires)
val request = NetworkMapService.RegistrationRequest(reg.toWire(storage.myLegalIdentityKey.private), net.myAddress)
val legalIdentityKey = obtainLegalIdentityKey()
val request = NetworkMapService.RegistrationRequest(reg.toWire(legalIdentityKey.private), net.myAddress)
return net.sendRequest(REGISTER_PROTOCOL_TOPIC, request, networkMapAddr, RunOnCallerThread)
}
protected open fun makeKeyManagementService(): KeyManagementService = PersistentKeyManagementService(setOf(storage.myLegalIdentityKey))
protected open fun makeKeyManagementService(): KeyManagementService = PersistentKeyManagementService(partyKeys)
open protected fun makeNetworkMapService() {
inNodeNetworkMapService = PersistentNetworkMapService(services)
@ -379,8 +385,8 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
val timestampChecker = TimestampChecker(platformClock, 30.seconds)
return when (type) {
SimpleNotaryService.Type -> SimpleNotaryService(services, timestampChecker, uniquenessProvider!!)
ValidatingNotaryService.Type -> ValidatingNotaryService(services, timestampChecker, uniquenessProvider!!)
SimpleNotaryService.type -> SimpleNotaryService(services, timestampChecker, uniquenessProvider!!)
ValidatingNotaryService.type -> ValidatingNotaryService(services, timestampChecker, uniquenessProvider!!)
else -> {
throw IllegalArgumentException("Notary type ${type.id} is not handled by makeNotaryService.")
}
@ -392,13 +398,14 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
protected open fun makeIdentityService(): IdentityService {
val service = InMemoryIdentityService()
service.registerIdentity(storage.myLegalIdentity)
service.registerIdentity(info.legalIdentity)
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.identity) }
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentity) }
netMapCache.changed.subscribe { mapChange ->
// TODO how should we handle network map removal
if (mapChange.type == MapChangeType.Added) {
service.registerIdentity(mapChange.node.identity)
service.registerIdentity(mapChange.node.legalIdentity)
}
}
@ -437,35 +444,42 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
val checkpointStorage = initialiseCheckpointService(dir)
val transactionStorage = PerFileTransactionStorage(dir.resolve("transactions"))
_servicesThatAcceptUploads += attachments
val (identity, keyPair) = obtainKeyPair(dir)
// Populate the partyKeys set.
obtainKeyPair(dir, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME)
for (service in advertisedServices) {
// Ensure all required keys exist.
obtainKeyPair(configuration.basedir, service.type.id + "-private-key", service.type.id + "-public", service.type.id)
}
val stateMachineTransactionMappingStorage = InMemoryStateMachineRecordedTransactionMappingStorage()
return Pair(
constructStorageService(attachments, transactionStorage, stateMachineTransactionMappingStorage, keyPair, identity),
constructStorageService(attachments, transactionStorage, stateMachineTransactionMappingStorage),
checkpointStorage
)
}
protected open fun constructStorageService(attachments: NodeAttachmentService,
transactionStorage: TransactionStorage,
stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage,
keyPair: KeyPair,
identity: Party) =
StorageServiceImpl(attachments, transactionStorage, stateMachineRecordedTransactionMappingStorage, keyPair, identity)
stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage) =
StorageServiceImpl(attachments, transactionStorage, stateMachineRecordedTransactionMappingStorage)
private fun obtainKeyPair(dir: Path): Pair<Party, KeyPair> {
protected fun obtainLegalIdentity(): Party = obtainKeyPair(configuration.basedir, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).first
protected fun obtainLegalIdentityKey(): KeyPair = obtainKeyPair(configuration.basedir, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).second
private fun obtainKeyPair(dir: Path, privateKeyFileName: String, publicKeyFileName: String, serviceName: String? = null): Pair<Party, KeyPair> {
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
// is distributed to other peers and we use it (or a key signed by it) when we need to do something
// "permissioned". The identity file is what gets distributed and contains the node's legal name along with
// the public key. Obviously in a real system this would need to be a certificate chain of some kind to ensure
// the legal name is actually validated in some way.
val privKeyFile = dir.resolve(PRIVATE_KEY_FILE_NAME)
val pubIdentityFile = dir.resolve(PUBLIC_IDENTITY_FILE_NAME)
val privKeyFile = dir.resolve(privateKeyFileName)
val pubIdentityFile = dir.resolve(publicKeyFileName)
val identityName = if (serviceName == null) configuration.myLegalName else configuration.myLegalName + "|" + serviceName
return if (!Files.exists(privKeyFile)) {
val identityAndKey = if (!Files.exists(privKeyFile)) {
log.info("Identity key not found, generating fresh key!")
val keyPair: KeyPair = generateKeyPair()
keyPair.serialize().writeToFile(privKeyFile)
val myIdentity = Party(configuration.myLegalName, keyPair.public)
val myIdentity = Party(identityName, keyPair.public)
// We include the Party class with the file here to help catch mixups when admins provide files of the
// wrong type by mistake.
myIdentity.serialize().writeToFile(pubIdentityFile)
@ -475,13 +489,15 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
// This is just a sanity check. It shouldn't fail unless the admin has fiddled with the files and messed
// things up for us.
val myIdentity = Files.readAllBytes(pubIdentityFile).deserialize<Party>()
if (myIdentity.name != configuration.myLegalName)
if (myIdentity.name != identityName)
throw ConfigurationException("The legal name in the config file doesn't match the stored identity file:" +
"${configuration.myLegalName} vs ${myIdentity.name}")
"${identityName} vs ${myIdentity.name}")
// Load the private key.
val keyPair = Files.readAllBytes(privKeyFile).deserialize<KeyPair>()
Pair(myIdentity, keyPair)
}
partyKeys += identityAndKey.second
return identityAndKey
}
protected open fun generateKeyPair() = com.r3corda.core.crypto.generateKeyPair()

View File

@ -117,7 +117,8 @@ class Node(override val configuration: FullNodeConfiguration, networkMapAddress:
artemisAddress
}()
}
val myIdentityOrNullIfNetworkMapService = if (networkMapService != null) services.storageService.myLegalIdentityKey.public else null
val legalIdentity = obtainLegalIdentity()
val myIdentityOrNullIfNetworkMapService = if (networkMapService != null) legalIdentity.owningKey else null
return NodeMessagingClient(configuration, serverAddr, myIdentityOrNullIfNetworkMapService, serverThread,
persistenceTx = { body: () -> Unit -> databaseTransaction(database) { body() } })
}

View File

@ -8,7 +8,6 @@ import com.r3corda.core.crypto.toStringShort
import com.r3corda.core.node.ServiceHub
import com.r3corda.core.node.services.Vault
import com.r3corda.core.transactions.TransactionBuilder
import com.r3corda.node.services.api.ServiceHubInternal
import com.r3corda.node.services.messaging.CordaRPCOps
import com.r3corda.node.services.messaging.StateMachineInfo
import com.r3corda.node.services.messaging.StateMachineUpdate
@ -93,10 +92,11 @@ class ServerRPCOps(
private fun exitCash(req: ClientToServiceCommand.ExitCash): TransactionBuildResult {
val builder: TransactionBuilder = TransactionType.General.Builder(null)
try {
val issuer = PartyAndReference(services.storageService.myLegalIdentity, req.issueRef)
val issuer = PartyAndReference(services.myInfo.legalIdentity, req.issueRef)
Cash().generateExit(builder, req.amount.issuedBy(issuer),
services.vaultService.currentVault.statesOfType<Cash.State>().filter { it.state.data.owner == issuer.party.owningKey })
builder.signWith(services.storageService.myLegalIdentityKey)
val myKey = services.legalIdentityKey
builder.signWith(myKey)
// Work out who the owners of the burnt states were
val inputStatesNullable = services.vaultService.statesForRefs(builder.inputStates())
@ -126,9 +126,10 @@ class ServerRPCOps(
// TODO: Make a lightweight protocol that manages this workflow, rather than embedding it directly in the service
private fun issueCash(req: ClientToServiceCommand.IssueCash): TransactionBuildResult {
val builder: TransactionBuilder = TransactionType.General.Builder(notary = null)
val issuer = PartyAndReference(services.storageService.myLegalIdentity, req.issueRef)
val issuer = PartyAndReference(services.myInfo.legalIdentity, req.issueRef)
Cash().generateIssue(builder, req.amount.issuedBy(issuer), req.recipient.owningKey, req.notary)
builder.signWith(services.storageService.myLegalIdentityKey)
val myKey = services.legalIdentityKey
builder.signWith(myKey)
val tx = builder.toSignedTransaction(checkSufficientSignatures = true)
// Issuance transactions do not need to be notarised, so we can skip directly to broadcasting it
val protocol = BroadcastTransactionProtocol(tx, setOf(req), setOf(req.recipient))

View File

@ -6,6 +6,7 @@ import com.r3corda.core.node.services.ServiceType
* Placeholder interface for regulator services.
*/
interface RegulatorService {
object Type : ServiceType("corda.regulator")
companion object {
val type = ServiceType.regulator
}
}

View File

@ -54,7 +54,7 @@ class FullNodeConfiguration(config: Config) : NodeConfiguration {
advertisedServices.add(ServiceInfo.parse(serviceId))
}
}
if (networkMapAddress == null) advertisedServices.add(ServiceInfo(NetworkMapService.Type))
if (networkMapAddress == null) advertisedServices.add(ServiceInfo(NetworkMapService.type))
val networkMapMessageAddress: SingleMessageRecipient? = if (networkMapAddress == null) null else NodeMessagingClient.makeNetworkMapAddress(networkMapAddress!!)
return Node(this, networkMapMessageAddress, advertisedServices)
}

View File

@ -41,11 +41,11 @@ import javax.annotation.concurrent.ThreadSafe
@ThreadSafe
open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCache {
override val networkMapNodes: List<NodeInfo>
get() = get(NetworkMapService.Type)
get() = get(NetworkMapService.type)
override val regulators: List<NodeInfo>
get() = get(RegulatorService.Type)
get() = get(ServiceType.regulator)
override val notaryNodes: List<NodeInfo>
get() = get(NotaryService.Type)
get() = get(ServiceType.notary)
override val partyNodes: List<NodeInfo>
get() = registeredNodes.map { it.value }
private val _changed = PublishSubject.create<MapChange>()
@ -58,10 +58,13 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach
protected var registeredNodes = Collections.synchronizedMap(HashMap<Party, NodeInfo>())
override fun get() = registeredNodes.map { it.value }
override fun get(serviceType: ServiceType) = registeredNodes.filterValues { it.advertisedServices.any { it.type.isSubTypeOf(serviceType) } }.map { it.value }
override fun get(serviceType: ServiceType) = registeredNodes.filterValues { it.advertisedServices.any { it.info.type.isSubTypeOf(serviceType) } }.map { it.value }
override fun getRecommended(type: ServiceType, contract: Contract, vararg party: Party): NodeInfo? = get(type).firstOrNull()
override fun getNodeByLegalName(name: String) = get().singleOrNull { it.identity.name == name }
override fun getNodeByPublicKey(publicKey: PublicKey) = get().singleOrNull { it.identity.owningKey == publicKey }
override fun getNodeByLegalName(name: String) = get().singleOrNull { it.legalIdentity.name == name }
override fun getNodeByPublicKey(publicKey: PublicKey) = get().singleOrNull {
(it.legalIdentity.owningKey == publicKey)
|| it.advertisedServices.any { it.identity.owningKey == publicKey }
}
override fun addMapService(net: MessagingService, networkMapAddress: SingleMessageRecipient, subscribe: Boolean,
ifChangedSinceVer: Int?): ListenableFuture<Unit> {
@ -96,7 +99,7 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach
}
override fun addNode(node: NodeInfo) {
val oldValue = registeredNodes.put(node.identity, node)
val oldValue = registeredNodes.put(node.legalIdentity, node)
if (oldValue == null) {
_changed.onNext(MapChange(node, oldValue, MapChangeType.Added))
} else if(oldValue != node) {
@ -105,7 +108,7 @@ open class InMemoryNetworkMapCache : SingletonSerializeAsToken(), NetworkMapCach
}
override fun removeNode(node: NodeInfo) {
val oldValue = registeredNodes.remove(node.identity)
val oldValue = registeredNodes.remove(node.legalIdentity)
_changed.onNext(MapChange(node, oldValue, MapChangeType.Removed))
}

View File

@ -48,7 +48,6 @@ import javax.annotation.concurrent.ThreadSafe
// a concept of identity changes over time, should that include the node for an identity? If so, that is likely to
// replace this service.
interface NetworkMapService {
object Type : ServiceType("corda.network_map")
companion object {
val DEFAULT_EXPIRATION_PERIOD = Period.ofWeeks(4)
@ -63,6 +62,8 @@ interface NetworkMapService {
val PUSH_ACK_PROTOCOL_TOPIC = "platform.network_map.push_ack"
val logger = loggerFor<NetworkMapService>()
val type = ServiceType.corda.getSubType("network_map")
}
val nodes: List<NodeInfo>
@ -270,7 +271,7 @@ abstract class AbstractNetworkMapService
// Update the current value atomically, so that if multiple updates come
// in on different threads, there is no risk of a race condition while checking
// sequence numbers.
val registrationInfo = registeredNodes.compute(node.identity, { mapKey: Party, existing: NodeRegistrationInfo? ->
val registrationInfo = registeredNodes.compute(node.legalIdentity, { mapKey: Party, existing: NodeRegistrationInfo? ->
changed = existing == null || existing.reg.serial < change.serial
if (changed) {
when (change.type) {
@ -332,7 +333,7 @@ class NodeRegistration(val node: NodeInfo, val serial: Long, val type: AddOrRemo
*/
fun toWire(privateKey: PrivateKey): WireNodeRegistration {
val regSerialized = this.serialize()
val regSig = privateKey.signWithECDSA(regSerialized.bits, node.identity.owningKey)
val regSig = privateKey.signWithECDSA(regSerialized.bits, node.legalIdentity.owningKey)
return WireNodeRegistration(regSerialized, regSig)
}
@ -346,7 +347,7 @@ class NodeRegistration(val node: NodeInfo, val serial: Long, val type: AddOrRemo
class WireNodeRegistration(raw: SerializedBytes<NodeRegistration>, sig: DigitalSignature.WithKey) : SignedData<NodeRegistration>(raw, sig) {
@Throws(IllegalArgumentException::class)
override fun verifyData(data: NodeRegistration) {
require(data.node.identity.owningKey == sig.by)
require(data.node.legalIdentity.owningKey == sig.by)
}
}

View File

@ -1,16 +1,12 @@
package com.r3corda.node.services.persistence
import com.r3corda.core.crypto.Party
import com.r3corda.core.node.services.AttachmentStorage
import com.r3corda.core.node.services.StateMachineRecordedTransactionMappingStorage
import com.r3corda.core.node.services.TransactionStorage
import com.r3corda.core.node.services.TxWritableStorageService
import com.r3corda.core.serialization.SingletonSerializeAsToken
import java.security.KeyPair
open class StorageServiceImpl(override val attachments: AttachmentStorage,
override val validatedTransactions: TransactionStorage,
override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage,
override val myLegalIdentityKey: KeyPair,
override val myLegalIdentity: Party = Party("Unit test party", myLegalIdentityKey.public))
override val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage)
: SingletonSerializeAsToken(), TxWritableStorageService

View File

@ -187,7 +187,7 @@ class ProtocolStateMachineImpl<R>(override val id: StateMachineRunId,
val session = ProtocolSession(sessionProtocol, otherParty, random63BitValue(), null)
openSessions[Pair(sessionProtocol, otherParty)] = session
val counterpartyProtocol = sessionProtocol.getCounterpartyMarker(otherParty).name
val sessionInit = SessionInit(session.ourSessionId, serviceHub.storageService.myLegalIdentity, counterpartyProtocol)
val sessionInit = SessionInit(session.ourSessionId, serviceHub.myInfo.legalIdentity, counterpartyProtocol)
val sessionInitResponse = sendAndReceiveInternal(session, sessionInit, SessionInitResponse::class.java)
if (sessionInitResponse is SessionConfirm) {
session.otherPartySessionId = sessionInitResponse.initiatedSessionId

View File

@ -386,7 +386,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
}
private fun sendSessionMessage(party: Party, message: SessionMessage, psm: ProtocolStateMachineImpl<*>?) {
val node = serviceHub.networkMapCache.getNodeByLegalName(party.name)
val node = serviceHub.networkMapCache.getNodeByPublicKey(party.owningKey)
?: throw IllegalArgumentException("Don't know about party $party")
val logger = psm?.logger ?: logger
logger.trace { "${psm?.id} sending $message to party $party" }

View File

@ -5,6 +5,7 @@ import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.serialization.SingletonSerializeAsToken
import com.r3corda.node.services.api.ServiceHubInternal
import com.r3corda.protocols.NotaryProtocol
import kotlin.reflect.KClass
/**
* A Notary service acts as the final signer of a transaction ensuring two things:
@ -16,9 +17,6 @@ import com.r3corda.protocols.NotaryProtocol
* This is the base implementation that can be customised with specific Notary transaction commit protocol.
*/
abstract class NotaryService(services: ServiceHubInternal) : SingletonSerializeAsToken() {
// Do not specify this as an advertised service. Use a concrete implementation.
// TODO: We do not want a service type that cannot be used. Fix the type system abuse here.
object Type : ServiceType("corda.notary")
init {
services.registerProtocolInitiator(NotaryProtocol.Client::class) { createProtocol(it) }

View File

@ -12,7 +12,9 @@ import com.r3corda.protocols.NotaryProtocol
class SimpleNotaryService(services: ServiceHubInternal,
val timestampChecker: TimestampChecker,
val uniquenessProvider: UniquenessProvider) : NotaryService(services) {
object Type : ServiceType("corda.notary.simple")
companion object {
val type = ServiceType.notary.getSubType("simple")
}
override fun createProtocol(otherParty: Party): NotaryProtocol.Service {
return NotaryProtocol.Service(otherParty, timestampChecker, uniquenessProvider)

View File

@ -11,7 +11,9 @@ import com.r3corda.protocols.ValidatingNotaryProtocol
class ValidatingNotaryService(services: ServiceHubInternal,
val timestampChecker: TimestampChecker,
val uniquenessProvider: UniquenessProvider) : NotaryService(services) {
object Type : ServiceType("corda.notary.validating")
companion object {
val type = ServiceType.notary.getSubType("validating")
}
override fun createProtocol(otherParty: Party): ValidatingNotaryProtocol {
return ValidatingNotaryProtocol(otherParty, timestampChecker, uniquenessProvider)

View File

@ -38,9 +38,9 @@ class ServerRPCTest {
@Before
fun setup() {
network = MockNetwork()
val networkMap = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.Type))
val networkMap = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.type))
aliceNode = network.createNode(networkMapAddress = networkMap.info.address)
notaryNode = network.createNode(advertisedServices = ServiceInfo(SimpleNotaryService.Type), networkMapAddress = networkMap.info.address)
notaryNode = network.createNode(advertisedServices = ServiceInfo(SimpleNotaryService.type), networkMapAddress = networkMap.info.address)
rpc = ServerRPCOps(aliceNode.services, aliceNode.smm, aliceNode.database)
stateMachineUpdates = rpc.stateMachinesAndUpdates().second
@ -57,13 +57,13 @@ class ServerRPCTest {
assertFalse(aliceNode.services.vaultService.currentVault.states.iterator().hasNext())
// Tell the monitoring service node to issue some cash
val recipient = aliceNode.services.storageService.myLegalIdentity
val outEvent = ClientToServiceCommand.IssueCash(Amount(quantity, GBP), ref, recipient, DUMMY_NOTARY)
val recipient = aliceNode.info.legalIdentity
val outEvent = ClientToServiceCommand.IssueCash(Amount(quantity, GBP), ref, recipient, notaryNode.info.notaryIdentity)
rpc.executeCommand(outEvent)
network.runNetwork()
val expectedState = Cash.State(Amount(quantity,
Issued(aliceNode.services.storageService.myLegalIdentity.ref(ref), GBP)),
Issued(aliceNode.info.legalIdentity.ref(ref), GBP)),
recipient.owningKey)
var issueSmId: StateMachineRunId? = null
@ -99,15 +99,15 @@ class ServerRPCTest {
rpc.executeCommand(ClientToServiceCommand.IssueCash(
amount = Amount(100, USD),
issueRef = OpaqueBytes(ByteArray(1, { 1 })),
recipient = aliceNode.services.storageService.myLegalIdentity,
notary = notaryNode.services.storageService.myLegalIdentity
recipient = aliceNode.info.legalIdentity,
notary = notaryNode.info.notaryIdentity
))
network.runNetwork()
rpc.executeCommand(ClientToServiceCommand.PayCash(
amount = Amount(100, Issued(PartyAndReference(aliceNode.services.storageService.myLegalIdentity, OpaqueBytes(ByteArray(1, { 1 }))), USD)),
recipient = aliceNode.services.storageService.myLegalIdentity
amount = Amount(100, Issued(PartyAndReference(aliceNode.info.legalIdentity, OpaqueBytes(ByteArray(1, { 1 }))), USD)),
recipient = aliceNode.info.legalIdentity
))
network.runNetwork()
@ -142,7 +142,7 @@ class ServerRPCTest {
val signaturePubKeys = tx.sigs.map { it.by }.toSet()
// Only Alice signed
require(signaturePubKeys.size == 1)
require(signaturePubKeys.contains(aliceNode.services.storageService.myLegalIdentity.owningKey))
require(signaturePubKeys.contains(aliceNode.info.legalIdentity.owningKey))
},
// MOVE
expect { tx ->
@ -151,8 +151,8 @@ class ServerRPCTest {
val signaturePubKeys = tx.sigs.map { it.by }.toSet()
// Alice and Notary signed
require(signaturePubKeys.size == 2)
require(signaturePubKeys.contains(aliceNode.services.storageService.myLegalIdentity.owningKey))
require(signaturePubKeys.contains(notaryNode.services.storageService.myLegalIdentity.owningKey))
require(signaturePubKeys.contains(aliceNode.info.legalIdentity.owningKey))
require(signaturePubKeys.contains(notaryNode.info.notaryIdentity.owningKey))
}
)
}

View File

@ -54,7 +54,7 @@ class AttachmentTests {
// Get node one to run a protocol to fetch it and insert it.
network.runNetwork()
val f1 = n1.services.startProtocol("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.identity))
val f1 = n1.services.startProtocol("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.legalIdentity))
network.runNetwork()
assertEquals(0, f1.get().fromDisk.size)
@ -65,7 +65,7 @@ class AttachmentTests {
// Shut down node zero and ensure node one can still resolve the attachment.
n0.stop()
val response: FetchDataProtocol.Result<Attachment> = n1.services.startProtocol("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.identity)).get()
val response: FetchDataProtocol.Result<Attachment> = n1.services.startProtocol("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.legalIdentity)).get()
assertEquals(attachment, response.fromDisk[0])
}
@ -76,7 +76,7 @@ class AttachmentTests {
// Get node one to fetch a non-existent attachment.
val hash = SecureHash.randomSHA256()
network.runNetwork()
val f1 = n1.services.startProtocol("tests.fetch2", FetchAttachmentsProtocol(setOf(hash), n0.info.identity))
val f1 = n1.services.startProtocol("tests.fetch2", FetchAttachmentsProtocol(setOf(hash), n0.info.legalIdentity))
network.runNetwork()
val e = assertFailsWith<FetchDataProtocol.HashNotFound> { rootCauseExceptions { f1.get() } }
assertEquals(hash, e.requested)
@ -96,7 +96,7 @@ class AttachmentTests {
}
}
}
}, true, null, null, ServiceInfo(NetworkMapService.Type), ServiceInfo(SimpleNotaryService.Type))
}, true, null, null, ServiceInfo(NetworkMapService.type), ServiceInfo(SimpleNotaryService.type))
val n1 = network.createNode(n0.info.address)
// Insert an attachment into node zero's store directly.
@ -109,7 +109,7 @@ class AttachmentTests {
// Get n1 to fetch the attachment. Should receive corrupted bytes.
network.runNetwork()
val f1 = n1.services.startProtocol("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.identity))
val f1 = n1.services.startProtocol("tests.fetch1", FetchAttachmentsProtocol(setOf(id), n0.info.legalIdentity))
network.runNetwork()
assertFailsWith<FetchDataProtocol.DownloadedVsRequestedDataMismatch> {
rootCauseExceptions { f1.get() }

View File

@ -41,7 +41,7 @@ class InMemoryMessagingTests {
@Test
fun basics() {
val node1 = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.Type))
val node1 = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.type))
val node2 = network.createNode(networkMapAddress = node1.info.address)
val node3 = network.createNode(networkMapAddress = node1.info.address)
@ -70,7 +70,7 @@ class InMemoryMessagingTests {
@Test
fun broadcast() {
val node1 = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.Type))
val node1 = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.type))
val node2 = network.createNode(networkMapAddress = node1.info.address)
val node3 = network.createNode(networkMapAddress = node1.info.address)
@ -89,7 +89,7 @@ class InMemoryMessagingTests {
*/
@Test
fun `skip unhandled messages`() {
val node1 = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.Type))
val node1 = network.createNode(advertisedServices = ServiceInfo(NetworkMapService.type))
val node2 = network.createNode(networkMapAddress = node1.info.address)
var received: Int = 0

View File

@ -8,11 +8,11 @@ import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.days
import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.ServiceHub
import com.r3corda.core.node.services.*
import com.r3corda.core.protocols.ProtocolStateMachine
import com.r3corda.core.protocols.StateMachineRunId
import com.r3corda.core.transactions.SignedTransaction
import com.r3corda.core.transactions.TransactionBuilder
import com.r3corda.core.transactions.WireTransaction
import com.r3corda.core.utilities.DUMMY_NOTARY
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
@ -85,16 +85,20 @@ class TwoPartyTradeProtocolTests {
notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY)
bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY)
val aliceKey = aliceNode.services.legalIdentityKey
val notaryKey = notaryNode.services.notaryIdentityKey
aliceNode.disableDBCloseOnStop()
bobNode.disableDBCloseOnStop()
databaseTransaction(bobNode.database) {
bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
bobNode.services.fillWithSomeTestCash(2000.DOLLARS, outputNotary = notaryNode.info.notaryIdentity)
}
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null).second
insertFakeTransactions(alicesFakePaper, aliceNode, aliceNode.storage.myLegalIdentityKey, notaryNode.storage.myLegalIdentityKey)
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey, notaryKey)
val (bobPsm, aliceResult) = runBuyerAndSeller("alice's paper".outputStateAndRef())
// TODO: Verify that the result was inserted into the transaction database.
@ -121,6 +125,8 @@ class TwoPartyTradeProtocolTests {
notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY)
bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY)
val aliceKey = aliceNode.services.legalIdentityKey
val notaryKey = notaryNode.services.notaryIdentityKey
val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle
val networkMapAddr = notaryNode.info.address
@ -128,11 +134,11 @@ class TwoPartyTradeProtocolTests {
net.runNetwork() // Clear network map registration messages
databaseTransaction(bobNode.database) {
bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
bobNode.services.fillWithSomeTestCash(2000.DOLLARS, outputNotary = notaryNode.info.notaryIdentity)
}
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null).second
insertFakeTransactions(alicesFakePaper, aliceNode, aliceNode.storage.myLegalIdentityKey)
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey, notaryKey)
val aliceFuture = runBuyerAndSeller("alice's paper".outputStateAndRef()).sellerResult
// Everything is on this thread so we can now step through the protocol one step at a time.
@ -200,11 +206,9 @@ class TwoPartyTradeProtocolTests {
override fun constructStorageService(
attachments: NodeAttachmentService,
transactionStorage: TransactionStorage,
stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage,
keyPair: KeyPair,
identity: Party
stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage
): StorageServiceImpl {
return StorageServiceImpl(attachments, RecordingTransactionStorage(transactionStorage), stateMachineRecordedTransactionMappingStorage, keyPair, identity)
return StorageServiceImpl(attachments, RecordingTransactionStorage(transactionStorage), stateMachineRecordedTransactionMappingStorage)
}
}
}
@ -216,6 +220,7 @@ class TwoPartyTradeProtocolTests {
notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name, ALICE_KEY)
bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name, BOB_KEY)
val aliceKey = aliceNode.services.legalIdentityKey
ledger(aliceNode.services) {
@ -228,11 +233,11 @@ class TwoPartyTradeProtocolTests {
}
val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray()))
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public).second
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public, notaryNode.info.notaryIdentity).second
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode)
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID).second
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, aliceNode.storage.myLegalIdentityKey)
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey)
net.runNetwork() // Clear network map registration messages
@ -307,6 +312,7 @@ class TwoPartyTradeProtocolTests {
notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
aliceNode = makeNodeWithTracking(notaryNode.info.address, ALICE.name, ALICE_KEY)
bobNode = makeNodeWithTracking(notaryNode.info.address, BOB.name, BOB_KEY)
val aliceKey = aliceNode.services.legalIdentityKey
ledger(aliceNode.services) {
@ -319,11 +325,11 @@ class TwoPartyTradeProtocolTests {
}
val attachmentID = attachment(ByteArrayInputStream(stream.toByteArray()))
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public).second
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public, notaryNode.info.notaryIdentity).second
insertFakeTransactions(bobsFakeCash, bobNode)
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID).second
insertFakeTransactions(alicesFakePaper, aliceNode, aliceNode.storage.myLegalIdentityKey)
val alicesFakePaper = fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID, notaryNode.info.notaryIdentity).second
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey)
net.runNetwork() // Clear network map registration messages
@ -387,9 +393,9 @@ class TwoPartyTradeProtocolTests {
private fun runBuyerAndSeller(assetToSell: StateAndRef<OwnableState>) : RunResult {
val buyerFuture = bobNode.initiateSingleShotProtocol(Seller::class) { otherParty ->
Buyer(otherParty, notaryNode.info.identity, 1000.DOLLARS, CommercialPaper.State::class.java)
Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java)
}
val seller = Seller(bobNode.info.identity, notaryNode.info, assetToSell, 1000.DOLLARS, ALICE_KEY)
val seller = Seller(bobNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, ALICE_KEY)
val sellerResultFuture = aliceNode.smm.add("seller", seller).resultFuture
return RunResult(buyerFuture, sellerResultFuture, seller.psm.id)
}
@ -402,15 +408,16 @@ class TwoPartyTradeProtocolTests {
notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name, ALICE_KEY)
bobNode = net.createPartyNode(notaryNode.info.address, BOB.name, BOB_KEY)
val aliceKey = aliceNode.services.legalIdentityKey
val bobKey = bobNode.services.legalIdentityKey
val issuer = MEGA_CORP.ref(1, 2, 3)
val bobKey = bobNode.keyManagement.freshKey()
val bobsBadCash = fillUpForBuyer(bobError, bobKey.public).second
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` issuer, null).second
val bobsBadCash = fillUpForBuyer(bobError, bobKey.public, notaryNode.info.notaryIdentity).second
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.info.legalIdentity.owningKey,
1200.DOLLARS `issued by` issuer, null, notaryNode.info.notaryIdentity).second
insertFakeTransactions(bobsBadCash, bobNode, bobNode.storage.myLegalIdentityKey, bobNode.storage.myLegalIdentityKey)
insertFakeTransactions(alicesFakePaper, aliceNode, aliceNode.storage.myLegalIdentityKey)
insertFakeTransactions(bobsBadCash, bobNode, bobKey)
insertFakeTransactions(alicesFakePaper, aliceNode, aliceKey)
net.runNetwork() // Clear network map registration messages
@ -452,14 +459,15 @@ class TwoPartyTradeProtocolTests {
private fun LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.fillUpForBuyer(
withError: Boolean,
owner: PublicKey = BOB_PUBKEY): Pair<Vault, List<WireTransaction>> {
owner: PublicKey = BOB_PUBKEY,
notary: Party): Pair<Vault, List<WireTransaction>> {
val issuer = DUMMY_CASH_ISSUER
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
// wants to sell to Bob.
val eb1 = transaction {
val eb1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
// Issued money to itself.
output("elbonian money 1") { 800.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
output("elbonian money 2") { 1000.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
output("elbonian money 1", notary = notary) { 800.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
output("elbonian money 2", notary = notary) { 1000.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
if (!withError)
command(DUMMY_CASH_ISSUER_KEY.public) { Cash.Commands.Issue() }
else
@ -474,17 +482,17 @@ class TwoPartyTradeProtocolTests {
}
// Bob gets some cash onto the ledger from BoE
val bc1 = transaction {
val bc1 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
input("elbonian money 1")
output("bob cash 1") { 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() }
this.verifies()
}
val bc2 = transaction {
val bc2 = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
input("elbonian money 2")
output("bob cash 2") { 300.DOLLARS.CASH `issued by` issuer `owned by` owner }
output { 700.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } // Change output.
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.
command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
this.verifies()
}
@ -497,9 +505,10 @@ class TwoPartyTradeProtocolTests {
withError: Boolean,
owner: PublicKey,
amount: Amount<Issued<Currency>>,
attachmentID: SecureHash?): Pair<Vault, List<WireTransaction>> {
val ap = transaction {
output("alice's paper") {
attachmentID: SecureHash?,
notary: Party): Pair<Vault, List<WireTransaction>> {
val ap = transaction(transactionBuilder = TransactionBuilder(notary = notary)) {
output("alice's paper", notary = notary) {
CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, amount, TEST_TX_TIME + 7.days)
}
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }

View File

@ -41,19 +41,19 @@ abstract class AbstractNetworkMapServiceTest {
// Confirm the service contains no nodes as own node only registered if network is run.
assertEquals(0, service().nodes.count())
assertNull(service().processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.identity, mapServiceNode.info.address, Long.MIN_VALUE)).node)
assertNull(service().processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.legalIdentity, mapServiceNode.info.address, Long.MIN_VALUE)).node)
// Register the new node
val instant = Instant.now()
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
val nodeKey = registerNode.storage.myLegalIdentityKey
val nodeKey = registerNode.services.legalIdentityKey
val addChange = NodeRegistration(registerNode.info, instant.toEpochMilli(), AddOrRemove.ADD, expires)
val addWireChange = addChange.toWire(nodeKey.private)
service().processRegistrationChangeRequest(RegistrationRequest(addWireChange, mapServiceNode.info.address, Long.MIN_VALUE))
swizzle()
assertEquals(1, service().nodes.count())
assertEquals(registerNode.info, service().processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.identity, mapServiceNode.info.address, Long.MIN_VALUE)).node)
assertEquals(registerNode.info, service().processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.legalIdentity, mapServiceNode.info.address, Long.MIN_VALUE)).node)
// Re-registering should be a no-op
service().processRegistrationChangeRequest(RegistrationRequest(addWireChange, mapServiceNode.info.address, Long.MIN_VALUE))
@ -67,7 +67,7 @@ abstract class AbstractNetworkMapServiceTest {
assert(service().processRegistrationChangeRequest(RegistrationRequest(removeWireChange, mapServiceNode.info.address, Long.MIN_VALUE)).success)
swizzle()
assertNull(service().processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.identity, mapServiceNode.info.address, Long.MIN_VALUE)).node)
assertNull(service().processQueryRequest(NetworkMapService.QueryIdentityRequest(registerNode.info.legalIdentity, mapServiceNode.info.address, Long.MIN_VALUE)).node)
swizzle()
// Trying to de-register a node that doesn't exist should fail
@ -88,7 +88,7 @@ abstract class AbstractNetworkMapServiceTest {
assertEquals(2, fetchPsm.get()?.count())
// Forcibly deregister the second node
val nodeKey = registerNode.storage.myLegalIdentityKey
val nodeKey = registerNode.services.legalIdentityKey
val instant = Instant.now()
val expires = instant + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
val reg = NodeRegistration(registerNode.info, instant.toEpochMilli()+1, AddOrRemove.REMOVE, expires)
@ -126,7 +126,7 @@ abstract class AbstractNetworkMapServiceTest {
assertEquals(0, service().getUnacknowledgedCount(registerNode.info.address, startingMapVersion))
// Fire off an update
val nodeKey = registerNode.storage.myLegalIdentityKey
val nodeKey = registerNode.services.legalIdentityKey
var seq = 0L
val expires = Instant.now() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
var reg = NodeRegistration(registerNode.info, seq++, AddOrRemove.ADD, expires)

View File

@ -3,6 +3,7 @@ package com.r3corda.node.services
import com.codahale.metrics.MetricRegistry
import com.google.common.util.concurrent.ListenableFuture
import com.r3corda.core.crypto.Party
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.*
import com.r3corda.core.protocols.ProtocolLogic
import com.r3corda.core.protocols.ProtocolLogicRefFactory
@ -51,6 +52,8 @@ open class MockServiceHubInternal(
get() = scheduler ?: throw UnsupportedOperationException()
override val clock: Clock
get() = overrideClock ?: throw UnsupportedOperationException()
override val myInfo: NodeInfo
get() = throw UnsupportedOperationException()
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
override val protocolLogicRefFactory: ProtocolLogicRefFactory

View File

@ -259,7 +259,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
private fun scheduleTX(instant: Instant, increment: Int = 1): ScheduledStateRef? {
var scheduledRef: ScheduledStateRef? = null
apply {
val freshKey = services.storageService.myLegalIdentityKey
val freshKey = services.keyManagementService.freshKey()
val state = TestState(factory.create(TestProtocolLogic::class.java, increment), instant)
val usefulTX = TransactionType.General.Builder(null).apply {
addOutputState(state, DUMMY_NOTARY)

View File

@ -36,18 +36,18 @@ class NotaryChangeTests {
oldNotaryNode = net.createNode(
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)
clientNodeB = net.createNode(networkMapAddress = oldNotaryNode.info.address)
newNotaryNode = net.createNode(networkMapAddress = oldNotaryNode.info.address, advertisedServices = ServiceInfo(SimpleNotaryService.Type))
newNotaryNode = net.createNode(networkMapAddress = oldNotaryNode.info.address, advertisedServices = ServiceInfo(SimpleNotaryService.type))
net.runNetwork() // Clear network map registration messages
}
@Test
fun `should change notary for a state with single participant`() {
val state = issueState(clientNodeA)
val newNotary = newNotaryNode.info.identity
val state = issueState(clientNodeA, oldNotaryNode)
val newNotary = newNotaryNode.info.notaryIdentity
val protocol = Instigator(state, newNotary)
val future = clientNodeA.services.startProtocol("notary-change", protocol)
@ -59,8 +59,8 @@ class NotaryChangeTests {
@Test
fun `should change notary for a state with multiple participants`() {
val state = issueMultiPartyState(clientNodeA, clientNodeB)
val newNotary = newNotaryNode.info.identity
val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode)
val newNotary = newNotaryNode.info.notaryIdentity
val protocol = Instigator(state, newNotary)
val future = clientNodeA.services.startProtocol("notary-change", protocol)
@ -75,7 +75,7 @@ class NotaryChangeTests {
@Test
fun `should throw when a participant refuses to change Notary`() {
val state = issueMultiPartyState(clientNodeA, clientNodeB)
val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode)
val newEvilNotary = Party("Evil Notary", generateKeyPair().public)
val protocol = Instigator(state, newEvilNotary)
val future = clientNodeA.services.startProtocol("notary-change", protocol)
@ -96,22 +96,27 @@ class NotaryChangeTests {
// - The transaction type is not a notary change transaction at all.
}
fun issueState(node: AbstractNode): StateAndRef<*> {
val tx = DummyContract.generateInitial(node.info.identity.ref(0), Random().nextInt(), DUMMY_NOTARY)
tx.signWith(node.storage.myLegalIdentityKey)
tx.signWith(DUMMY_NOTARY_KEY)
fun issueState(node: AbstractNode, notaryNode: AbstractNode): StateAndRef<*> {
val tx = DummyContract.generateInitial(node.info.legalIdentity.ref(0), Random().nextInt(), notaryNode.info.notaryIdentity)
val nodeKey = node.services.legalIdentityKey
tx.signWith(nodeKey)
val notaryKeyPair = notaryNode.services.notaryIdentityKey
tx.signWith(notaryKeyPair)
val stx = tx.toSignedTransaction()
node.services.recordTransactions(listOf(stx))
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
}
fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode): StateAndRef<DummyContract.MultiOwnerState> {
fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode, notaryNode: AbstractNode): StateAndRef<DummyContract.MultiOwnerState> {
val state = TransactionState(DummyContract.MultiOwnerState(0,
listOf(nodeA.info.identity.owningKey, nodeB.info.identity.owningKey)), DUMMY_NOTARY)
val tx = TransactionType.NotaryChange.Builder(DUMMY_NOTARY).withItems(state)
tx.signWith(nodeA.storage.myLegalIdentityKey)
tx.signWith(nodeB.storage.myLegalIdentityKey)
tx.signWith(DUMMY_NOTARY_KEY)
listOf(nodeA.info.legalIdentity.owningKey, nodeB.info.legalIdentity.owningKey)), notaryNode.info.notaryIdentity)
val tx = TransactionType.NotaryChange.Builder(notaryNode.info.notaryIdentity).withItems(state)
val nodeAKey = nodeA.services.legalIdentityKey
val nodeBKey = nodeB.services.legalIdentityKey
tx.signWith(nodeAKey)
tx.signWith(nodeBKey)
val notaryKeyPair = notaryNode.services.notaryIdentityKey
tx.signWith(notaryKeyPair)
val stx = tx.toSignedTransaction()
nodeA.services.recordTransactions(listOf(stx))
nodeB.services.recordTransactions(listOf(stx))
@ -119,11 +124,12 @@ fun issueMultiPartyState(nodeA: AbstractNode, nodeB: AbstractNode): StateAndRef<
return stateAndRef
}
fun issueInvalidState(node: AbstractNode, notary: Party = DUMMY_NOTARY): StateAndRef<*> {
val tx = DummyContract.generateInitial(node.info.identity.ref(0), Random().nextInt(), notary)
fun issueInvalidState(node: AbstractNode, notary: Party): StateAndRef<*> {
val tx = DummyContract.generateInitial(node.info.legalIdentity.ref(0), Random().nextInt(), notary)
tx.setTime(Instant.now(), 30.seconds)
tx.signWith(node.storage.myLegalIdentityKey)
val nodeKey = node.services.legalIdentityKey
tx.signWith(nodeKey)
val stx = tx.toSignedTransaction(false)
node.services.recordTransactions(listOf(stx))
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
}
}

View File

@ -1,6 +1,9 @@
package com.r3corda.node.services
import com.google.common.util.concurrent.ListenableFuture
import com.r3corda.core.contracts.DummyContract
import com.r3corda.core.contracts.StateAndRef
import com.r3corda.core.contracts.StateRef
import com.r3corda.core.contracts.TransactionType
import com.r3corda.core.node.services.ServiceInfo
import com.r3corda.core.crypto.DigitalSignature
@ -8,6 +11,7 @@ import com.r3corda.core.seconds
import com.r3corda.core.transactions.SignedTransaction
import com.r3corda.core.utilities.DUMMY_NOTARY
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
import com.r3corda.node.internal.AbstractNode
import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.services.transactions.SimpleNotaryService
import com.r3corda.protocols.NotaryError
@ -18,6 +22,7 @@ import com.r3corda.testing.node.MockNetwork
import org.junit.Before
import org.junit.Test
import java.time.Instant
import java.util.*
import java.util.concurrent.ExecutionException
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -33,7 +38,7 @@ class NotaryServiceTests {
notaryNode = net.createNode(
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)
net.runNetwork() // Clear network map registration messages
}
@ -41,7 +46,7 @@ class NotaryServiceTests {
@Test fun `should sign a unique transaction with a valid timestamp`() {
val stx = run {
val inputState = issueState(clientNode)
val tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState)
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
tx.setTime(Instant.now(), 30.seconds)
tx.signWith(clientNode.keyPair!!)
tx.toSignedTransaction(false)
@ -55,7 +60,7 @@ class NotaryServiceTests {
@Test fun `should sign a unique transaction without a timestamp`() {
val stx = run {
val inputState = issueState(clientNode)
val tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState)
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
tx.signWith(clientNode.keyPair!!)
tx.toSignedTransaction(false)
}
@ -68,7 +73,7 @@ class NotaryServiceTests {
@Test fun `should report error for transaction with an invalid timestamp`() {
val stx = run {
val inputState = issueState(clientNode)
val tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState)
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
tx.setTime(Instant.now().plusSeconds(3600), 30.seconds)
tx.signWith(clientNode.keyPair!!)
tx.toSignedTransaction(false)
@ -84,7 +89,7 @@ class NotaryServiceTests {
@Test fun `should report conflict for a duplicate transaction`() {
val stx = run {
val inputState = issueState(clientNode)
val tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState)
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
tx.signWith(clientNode.keyPair!!)
tx.toSignedTransaction(false)
}
@ -109,4 +114,15 @@ class NotaryServiceTests {
net.runNetwork()
return future
}
fun issueState(node: AbstractNode): StateAndRef<*> {
val tx = DummyContract.generateInitial(node.info.legalIdentity.ref(0), Random().nextInt(), notaryNode.info.notaryIdentity)
val nodeKey = node.services.legalIdentityKey
tx.signWith(nodeKey)
val notaryKeyPair = notaryNode.services.notaryIdentityKey
tx.signWith(notaryKeyPair)
val stx = tx.toSignedTransaction()
node.services.recordTransactions(listOf(stx))
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
}
}

View File

@ -1,14 +1,13 @@
package com.r3corda.node.services
import com.google.common.util.concurrent.ListenableFuture
import com.r3corda.core.contracts.Command
import com.r3corda.core.contracts.DummyContract
import com.r3corda.core.contracts.TransactionType
import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.DigitalSignature
import com.r3corda.core.node.services.ServiceInfo
import com.r3corda.core.transactions.SignedTransaction
import com.r3corda.core.utilities.DUMMY_NOTARY
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
import com.r3corda.node.internal.AbstractNode
import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.services.transactions.ValidatingNotaryService
import com.r3corda.protocols.NotaryError
@ -20,6 +19,7 @@ import com.r3corda.testing.node.MockNetwork
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import java.util.*
import java.util.concurrent.ExecutionException
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -34,7 +34,7 @@ class ValidatingNotaryServiceTests {
notaryNode = net.createNode(
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)
net.runNetwork() // Clear network map registration messages
@ -42,8 +42,8 @@ class ValidatingNotaryServiceTests {
@Test fun `should report error for invalid transaction dependency`() {
val stx = run {
val inputState = issueInvalidState(clientNode)
val tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState)
val inputState = issueInvalidState(clientNode, notaryNode.info.notaryIdentity)
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState)
tx.signWith(clientNode.keyPair!!)
tx.toSignedTransaction(false)
}
@ -61,7 +61,7 @@ class ValidatingNotaryServiceTests {
val inputState = issueState(clientNode)
val command = Command(DummyContract.Commands.Move(), expectedMissingKey)
val tx = TransactionType.General.Builder(DUMMY_NOTARY).withItems(inputState, command)
val tx = TransactionType.General.Builder(notaryNode.info.notaryIdentity).withItems(inputState, command)
tx.signWith(clientNode.keyPair!!)
tx.toSignedTransaction(false)
}
@ -82,4 +82,15 @@ class ValidatingNotaryServiceTests {
net.runNetwork()
return future
}
fun issueState(node: AbstractNode): StateAndRef<*> {
val tx = DummyContract.generateInitial(node.info.legalIdentity.ref(0), Random().nextInt(), notaryNode.info.notaryIdentity)
val nodeKey = node.services.legalIdentityKey
tx.signWith(nodeKey)
val notaryKeyPair = notaryNode.services.notaryIdentityKey
tx.signWith(notaryKeyPair)
val stx = tx.toSignedTransaction()
node.services.recordTransactions(listOf(stx))
return StateAndRef(tx.outputStates().first(), StateRef(stx.id, 0))
}
}

View File

@ -84,7 +84,7 @@ class VaultWithCashTest {
fun `issue and spend total correctly and irrelevant ignored`() {
databaseTransaction(database) {
// A tx that sends us money.
val freshKey = services.storageService.myLegalIdentityKey
val freshKey = services.keyManagementService.freshKey()
val usefulTX = TransactionType.General.Builder(null).apply {
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
signWith(MEGA_CORP_KEY)
@ -122,7 +122,7 @@ class VaultWithCashTest {
@Test
fun `branching LinearStates fails to verify`() {
databaseTransaction(database) {
val freshKey = services.storageService.myLegalIdentityKey
val freshKey = services.keyManagementService.freshKey()
val linearId = UniqueIdentifier()
// Issue a linear state
@ -142,7 +142,7 @@ class VaultWithCashTest {
@Test
fun `sequencing LinearStates works`() {
databaseTransaction(database) {
val freshKey = services.storageService.myLegalIdentityKey
val freshKey = services.keyManagementService.freshKey()
val linearId = UniqueIdentifier()

View File

@ -33,8 +33,8 @@ class DataVendingServiceTests {
@Test
fun `notify of transaction`() {
val (vaultServiceNode, registerNode) = network.createTwoNodes()
val beneficiary = vaultServiceNode.services.storageService.myLegalIdentityKey.public
val deposit = registerNode.services.storageService.myLegalIdentity.ref(1)
val beneficiary = vaultServiceNode.info.legalIdentity.owningKey
val deposit = registerNode.info.legalIdentity.ref(1)
network.runNetwork()
// Generate an issuance transaction
@ -42,7 +42,8 @@ class DataVendingServiceTests {
Cash().generateIssue(ptx, Amount(100, Issued(deposit, USD)), beneficiary, DUMMY_NOTARY)
// Complete the cash transaction, and then manually relay it
ptx.signWith(registerNode.services.storageService.myLegalIdentityKey)
val registerKey = registerNode.services.legalIdentityKey
ptx.signWith(registerKey)
val tx = ptx.toSignedTransaction()
assertEquals(0, vaultServiceNode.services.vaultService.currentVault.states.toList().size)
@ -61,7 +62,7 @@ class DataVendingServiceTests {
@Test
fun `notify failure`() {
val (vaultServiceNode, registerNode) = network.createTwoNodes()
val beneficiary = vaultServiceNode.services.storageService.myLegalIdentityKey.public
val beneficiary = vaultServiceNode.info.legalIdentity.owningKey
val deposit = MEGA_CORP.ref(1)
network.runNetwork()
@ -70,7 +71,8 @@ class DataVendingServiceTests {
Cash().generateIssue(ptx, Amount(100, Issued(deposit, USD)), beneficiary, DUMMY_NOTARY)
// The transaction tries issuing MEGA_CORP cash, but we aren't the issuer, so it's invalid
ptx.signWith(registerNode.services.storageService.myLegalIdentityKey)
val registerKey = registerNode.services.legalIdentityKey
ptx.signWith(registerKey)
val tx = ptx.toSignedTransaction(false)
assertEquals(0, vaultServiceNode.services.vaultService.currentVault.states.toList().size)
@ -82,7 +84,7 @@ class DataVendingServiceTests {
private fun MockNode.sendNotifyTx(tx: SignedTransaction, walletServiceNode: MockNode) {
walletServiceNode.services.registerProtocolInitiator(NotifyTxProtocol::class, ::NotifyTransactionHandler)
services.startProtocol("notify-tx", NotifyTxProtocol(walletServiceNode.info.identity, tx))
services.startProtocol("notify-tx", NotifyTxProtocol(walletServiceNode.info.legalIdentity, tx))
network.runNetwork()
}

View File

@ -60,7 +60,7 @@ class StateMachineManagerTests {
fun `protocol restarted just after receiving payload`() {
node2.services.registerProtocolInitiator(SendProtocol::class) { ReceiveThenSuspendProtocol(it) }
val payload = random63BitValue()
node1.smm.add("test", SendProtocol(payload, node2.info.identity))
node1.smm.add("test", SendProtocol(payload, node2.info.legalIdentity))
// We push through just enough messages to get only the SessionData sent
// TODO We should be able to give runNetwork a predicate for when to stop
@ -108,7 +108,7 @@ class StateMachineManagerTests {
fun `protocol loaded from checkpoint will respond to messages from before start`() {
val payload = random63BitValue()
node1.services.registerProtocolInitiator(ReceiveThenSuspendProtocol::class) { SendProtocol(payload, it) }
val receiveProtocol = ReceiveThenSuspendProtocol(node1.info.identity)
val receiveProtocol = ReceiveThenSuspendProtocol(node1.info.legalIdentity)
node2.smm.add("test", receiveProtocol) // Prepare checkpointed receive protocol
node2.stop() // kill receiver
val restoredProtocol = node2.restartAndGetRestoredProtocol<ReceiveThenSuspendProtocol>(node1.info.address)
@ -135,7 +135,7 @@ class StateMachineManagerTests {
}
// Kick off first send and receive
node2.smm.add("test", PingPongProtocol(node3.info.identity, payload))
node2.smm.add("test", PingPongProtocol(node3.info.legalIdentity, payload))
assertEquals(1, node2.checkpointStorage.checkpoints().count())
// Restart node and thus reload the checkpoint and resend the message with same UUID
node2.stop()
@ -165,7 +165,7 @@ class StateMachineManagerTests {
node2.services.registerProtocolInitiator(SendProtocol::class) { ReceiveThenSuspendProtocol(it) }
node3.services.registerProtocolInitiator(SendProtocol::class) { ReceiveThenSuspendProtocol(it) }
val payload = random63BitValue()
node1.smm.add("multiple-send", SendProtocol(payload, node2.info.identity, node3.info.identity))
node1.smm.add("multiple-send", SendProtocol(payload, node2.info.legalIdentity, node3.info.legalIdentity))
net.runNetwork()
val node2Protocol = node2.getSingleProtocol<ReceiveThenSuspendProtocol>().first
val node3Protocol = node3.getSingleProtocol<ReceiveThenSuspendProtocol>().first
@ -181,7 +181,7 @@ class StateMachineManagerTests {
val node3Payload = random63BitValue()
node2.services.registerProtocolInitiator(ReceiveThenSuspendProtocol::class) { SendProtocol(node2Payload, it) }
node3.services.registerProtocolInitiator(ReceiveThenSuspendProtocol::class) { SendProtocol(node3Payload, it) }
val multiReceiveProtocol = ReceiveThenSuspendProtocol(node2.info.identity, node3.info.identity)
val multiReceiveProtocol = ReceiveThenSuspendProtocol(node2.info.legalIdentity, node3.info.legalIdentity)
node1.smm.add("multiple-receive", multiReceiveProtocol)
net.runNetwork(1) // session handshaking
// have the messages arrive in reverse order of receive
@ -195,7 +195,7 @@ class StateMachineManagerTests {
@Test
fun `exception thrown on other side`() {
node2.services.registerProtocolInitiator(ReceiveThenSuspendProtocol::class) { ExceptionProtocol }
val future = node1.smm.add("exception", ReceiveThenSuspendProtocol(node2.info.identity)).resultFuture
val future = node1.smm.add("exception", ReceiveThenSuspendProtocol(node2.info.legalIdentity)).resultFuture
net.runNetwork()
assertThatThrownBy { future.get() }.hasCauseInstanceOf(ProtocolSessionException::class.java)
}