From 34e52551fda34a5de12613b54677a70e4b8f95c6 Mon Sep 17 00:00:00 2001 From: Michele Sollecito Date: Mon, 25 Jun 2018 11:59:43 +0100 Subject: [PATCH 1/5] [CORDA-1663]: Node won't start if cordapps generate states prior to deletion (fix). (#3432) --- .../node/services/vault/NodeVaultService.kt | 92 ++++++++++++++----- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt index 0826ef094b..cf9b1ba9f2 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt @@ -2,21 +2,54 @@ package net.corda.node.services.vault import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.strands.Strand -import net.corda.core.contracts.* +import net.corda.core.contracts.Amount +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.FungibleAsset +import net.corda.core.contracts.OwnableState +import net.corda.core.contracts.StateAndRef +import net.corda.core.contracts.StateRef import net.corda.core.crypto.SecureHash -import net.corda.core.internal.* +import net.corda.core.internal.ThreadBox +import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.bufferUntilSubscribed +import net.corda.core.internal.tee +import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.DataFeed import net.corda.core.node.ServicesForResolution import net.corda.core.node.StatesToRecord -import net.corda.core.node.services.* -import net.corda.core.node.services.vault.* +import net.corda.core.node.services.KeyManagementService +import net.corda.core.node.services.StatesNotAvailableException +import net.corda.core.node.services.Vault +import net.corda.core.node.services.VaultQueryException +import net.corda.core.node.services.queryBy +import net.corda.core.node.services.vault.DEFAULT_PAGE_NUM +import net.corda.core.node.services.vault.DEFAULT_PAGE_SIZE +import net.corda.core.node.services.vault.MAX_PAGE_SIZE +import net.corda.core.node.services.vault.PageSpecification +import net.corda.core.node.services.vault.QueryCriteria +import net.corda.core.node.services.vault.Sort +import net.corda.core.node.services.vault.SortAttribute +import net.corda.core.node.services.vault.builder import net.corda.core.schemas.PersistentStateRef import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.transactions.* -import net.corda.core.utilities.* +import net.corda.core.transactions.ContractUpgradeWireTransaction +import net.corda.core.transactions.CoreTransaction +import net.corda.core.transactions.FullTransaction +import net.corda.core.transactions.NotaryChangeWireTransaction +import net.corda.core.transactions.WireTransaction +import net.corda.core.utilities.NonEmptySet +import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.debug +import net.corda.core.utilities.toHexString +import net.corda.core.utilities.toNonEmptySet +import net.corda.core.utilities.trace import net.corda.node.services.api.VaultServiceInternal import net.corda.node.services.statemachine.FlowStateMachineImpl -import net.corda.nodeapi.internal.persistence.* +import net.corda.nodeapi.internal.persistence.CordaPersistence +import net.corda.nodeapi.internal.persistence.HibernateConfiguration +import net.corda.nodeapi.internal.persistence.bufferUntilDatabaseCommit +import net.corda.nodeapi.internal.persistence.currentDBSession +import net.corda.nodeapi.internal.persistence.wrapWithDatabaseTransaction import org.hibernate.Session import rx.Observable import rx.subjects.PublishSubject @@ -132,7 +165,8 @@ class NodeVaultService( val ourNewStates = when (statesToRecord) { StatesToRecord.NONE -> throw AssertionError("Should not reach here") StatesToRecord.ONLY_RELEVANT -> tx.outputs.withIndex().filter { - isRelevant(it.value.data, keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } }).toSet()) } + isRelevant(it.value.data, keyManagementService.filterMyKeys(tx.outputs.flatMap { it.data.participants.map { it.owningKey } }).toSet()) + } StatesToRecord.ALL_VISIBLE -> tx.outputs.withIndex() }.map { tx.outRef(it.index) } @@ -158,16 +192,13 @@ class NodeVaultService( else -> throw IllegalArgumentException("Unsupported transaction type: ${tx.javaClass.name}") } val myKeys by lazy { keyManagementService.filterMyKeys(ltx.outputs.flatMap { it.data.participants.map { it.owningKey } }) } - val (consumedStateAndRefs, producedStates) = ltx.inputs. - zip(ltx.outputs). - filter { (_, output) -> - if (statesToRecord == StatesToRecord.ONLY_RELEVANT) { - isRelevant(output.data, myKeys.toSet()) - } else { - true - } - }. - unzip() + val (consumedStateAndRefs, producedStates) = ltx.inputs.zip(ltx.outputs).filter { (_, output) -> + if (statesToRecord == StatesToRecord.ONLY_RELEVANT) { + isRelevant(output.data, myKeys.toSet()) + } else { + true + } + }.unzip() val producedStateAndRefs = producedStates.map { ltx.outRef(it.data) } if (consumedStateAndRefs.isEmpty() && producedStateAndRefs.isEmpty()) { @@ -393,7 +424,7 @@ class NodeVaultService( if (!seen) { val contractInterfaces = deriveContractInterfaces(concreteType) contractInterfaces.map { - val contractInterface = contractStateTypeMappings.getOrPut(it.name, { mutableSetOf() }) + val contractInterface = contractStateTypeMappings.getOrPut(it.name) { mutableSetOf() } contractInterface.add(concreteType.name) } } @@ -461,7 +492,7 @@ class NodeVaultService( if (!paging.isDefault && index == paging.pageSize) // skip last result if paged return@forEachIndexed val vaultState = result[0] as VaultSchemaV1.VaultStates - val stateRef = StateRef(SecureHash.parse(vaultState.stateRef!!.txId!!), vaultState.stateRef!!.index!!) + val stateRef = StateRef(SecureHash.parse(vaultState.stateRef!!.txId), vaultState.stateRef!!.index) stateRefs.add(stateRef) statesMeta.add(Vault.StateMetadata(stateRef, vaultState.contractStateClassName, @@ -519,13 +550,24 @@ class NodeVaultService( val distinctTypes = results.map { it } val contractInterfaceToConcreteTypes = mutableMapOf>() + val unknownTypes = mutableSetOf() distinctTypes.forEach { type -> - val concreteType: Class = uncheckedCast(Class.forName(type)) - val contractInterfaces = deriveContractInterfaces(concreteType) - contractInterfaces.map { - val contractInterface = contractInterfaceToConcreteTypes.getOrPut(it.name, { mutableSetOf() }) - contractInterface.add(concreteType.name) + val concreteType: Class? = try { + uncheckedCast(Class.forName(type)) + } catch (e: ClassNotFoundException) { + unknownTypes += type + null } + concreteType?.let { + val contractInterfaces = deriveContractInterfaces(it) + contractInterfaces.map { + val contractInterface = contractInterfaceToConcreteTypes.getOrPut(it.name) { mutableSetOf() } + contractInterface.add(it.name) + } + } + } + if (unknownTypes.isNotEmpty()) { + log.warn("There are unknown contract state types in the vault, which will prevent these states from being used. The relevant CorDapps must be loaded for these states to be used. The types not on the classpath are ${unknownTypes.joinToString(", ", "[", "]")}.") } return contractInterfaceToConcreteTypes } From 9be4c5dca4b982dc83e185f43ce19d1776d00ce7 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Mon, 25 Jun 2018 13:01:33 +0100 Subject: [PATCH 2/5] CORDA-1567 Remove all traces of the out-of-process verifier (#3424) --- docs/source/changelog.rst | 1 + docs/source/corda-api.rst | 1 - docs/source/corda-repo-layout.rst | 1 - .../design/monitoring-management/design.md | 3 +- docs/source/out-of-process-verification.rst | 26 ------- .../kotlin/net/corda/nodeapi/VerifierApi.kt | 62 ---------------- .../kotlin/net/corda/node/internal/Node.kt | 17 +---- .../node/services/config/NodeConfiguration.kt | 3 +- .../messaging/VerifierMessagingClient.kt | 74 ------------------- .../OutOfProcessTransactionVerifierService.kt | 71 ------------------ .../net/corda/testing/driver/DriverDSL.kt | 3 +- 11 files changed, 6 insertions(+), 256 deletions(-) delete mode 100644 docs/source/out-of-process-verification.rst delete mode 100644 node-api/src/main/kotlin/net/corda/nodeapi/VerifierApi.kt delete mode 100644 node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt delete mode 100644 node/src/main/kotlin/net/corda/node/services/transactions/OutOfProcessTransactionVerifierService.kt diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 3381a3fd01..9bb8267023 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -6,6 +6,7 @@ release, see :doc:`upgrade-notes`. Unreleased ---------- +* Remove all references to the out-of-process transaction verification. * The class carpenter has a "lenient" mode where it will, during deserialisation, happily synthesis classes that implement interfaces that will have unimplemented methods. This is useful, for example, for object viewers. This can be turned on diff --git a/docs/source/corda-api.rst b/docs/source/corda-api.rst index c967d7431e..9e79e9d8a7 100644 --- a/docs/source/corda-api.rst +++ b/docs/source/corda-api.rst @@ -90,7 +90,6 @@ The following modules are available but we do not commit to their stability or c * **net.corda.tools.explorer**: a GUI front-end for Corda * **net.corda.tools.graphs**: utilities to infer project dependencies * **net.corda.tools.loadtest**: Corda load tests -* **net.corda.verifier**: allows out-of-node transaction verification, allowing verification to scale horizontally * **net.corda.webserver**: is a servlet container for CorDapps that export HTTP endpoints. This server is an RPC client of the node * **net.corda.sandbox-creator**: sandbox utilities * **net.corda.quasar.hook**: agent to hook into Quasar and provide types exclusion lists diff --git a/docs/source/corda-repo-layout.rst b/docs/source/corda-repo-layout.rst index c297603609..c280cf4fef 100644 --- a/docs/source/corda-repo-layout.rst +++ b/docs/source/corda-repo-layout.rst @@ -23,5 +23,4 @@ The Corda repository comprises the following folders: mock network) implementation * **tools** contains the explorer which is a GUI front-end for Corda, and also the DemoBench which is a GUI tool that allows you to run Corda nodes locally for demonstrations -* **verifier** allows out-of-node transaction verification, allowing verification to scale horizontally * **webserver** is a servlet container for CorDapps that export HTTP endpoints. This server is an RPC client of the node \ No newline at end of file diff --git a/docs/source/design/monitoring-management/design.md b/docs/source/design/monitoring-management/design.md index 2c0515c980..f90af477e5 100644 --- a/docs/source/design/monitoring-management/design.md +++ b/docs/source/design/monitoring-management/design.md @@ -232,7 +232,7 @@ In general, the requirements outlined in this design are cross-cutting concerns * `FlowErrorAuditEvent` (unused) * `SystemAuditEvent` (unused) * Modules impacted - * All modules packaged and shipped as part of a Corda distribution (as published to Artifactory / Maven): *core, node, node-api, node-driver, finance, confidential-identities, test-common, test-utils, verifier, webserver, jackson, jfx, mock, rpc* + * All modules packaged and shipped as part of a Corda distribution (as published to Artifactory / Maven): *core, node, node-api, node-driver, finance, confidential-identities, test-common, test-utils, webserver, jackson, jfx, mock, rpc* ### Functional @@ -458,7 +458,6 @@ Corda subsystem components: | NotaryService | RaftNonValidatingNotaryService | as above | | NotaryService | BFTNonValidatingNotaryService | Logging coverage (info, debug) | | Doorman | DoormanServer (Enterprise only) | Some logging (info, warn, error), and use of `println` | -| TransactionVerifierService | OutOfProcessTransactionVerifierService (Enterprise only) | some logging (info) | | | | | Corda core flows: diff --git a/docs/source/out-of-process-verification.rst b/docs/source/out-of-process-verification.rst deleted file mode 100644 index 269fc37eaf..0000000000 --- a/docs/source/out-of-process-verification.rst +++ /dev/null @@ -1,26 +0,0 @@ -Out-of-process verification -=========================== - -A Corda node does transaction verification through ``ServiceHub.transactionVerifierService``. This is by default an -``InMemoryTransactionVerifierService`` which just verifies transactions in-process. - -Corda may be configured to use out of process verification. Any number of verifiers may be started connecting to a node -through the node's exposed artemis SSL port. The messaging layer takes care of load balancing. - -.. note:: We plan to introduce kernel level sandboxing around the out of process verifiers as an additional line of - defence in case of inner sandbox escapes. - -To configure a node to use out of process verification specify the ``verifierType`` option in your node.conf: - -.. literalinclude:: example-code/src/main/resources/example-out-of-process-verifier-node.conf - :language: cfg - -You can build a verifier jar using ``./gradlew verifier:standaloneJar``. - -And run it with ``java -jar verifier/build/libs/corda-verifier.jar ``. - -``PATH_TO_VERIFIER_BASE_DIR`` should contain a ``certificates`` folder akin to the one in a node directory, and a -``verifier.conf`` containing the following: - -.. literalinclude:: example-code/src/main/resources/example-verifier.conf - :language: cfg diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/VerifierApi.kt b/node-api/src/main/kotlin/net/corda/nodeapi/VerifierApi.kt deleted file mode 100644 index ca9f03cc07..0000000000 --- a/node-api/src/main/kotlin/net/corda/nodeapi/VerifierApi.kt +++ /dev/null @@ -1,62 +0,0 @@ -package net.corda.nodeapi - -import net.corda.core.serialization.* -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.utilities.sequence -import org.apache.activemq.artemis.api.core.SimpleString -import org.apache.activemq.artemis.api.core.client.ClientMessage -import org.apache.activemq.artemis.reader.MessageUtil - -object VerifierApi { - const val VERIFIER_USERNAME = "SystemUsers/Verifier" - const val VERIFICATION_REQUESTS_QUEUE_NAME = "verifier.requests" - const val VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX = "verifier.responses" - private const val VERIFICATION_ID_FIELD_NAME = "id" - private const val RESULT_EXCEPTION_FIELD_NAME = "result-exception" - - data class VerificationRequest( - val verificationId: Long, - val transaction: LedgerTransaction, - val responseAddress: SimpleString - ) { - companion object { - fun fromClientMessage(message: ClientMessage): ObjectWithCompatibleContext { - val bytes = ByteArray(message.bodySize).apply { message.bodyBuffer.readBytes(this) } - val bytesSequence = bytes.sequence() - val (transaction, context) = bytesSequence.deserializeWithCompatibleContext() - val request = VerificationRequest( - message.getLongProperty(VERIFICATION_ID_FIELD_NAME), - transaction, - MessageUtil.getJMSReplyTo(message)) - return ObjectWithCompatibleContext(request, context) - } - } - - fun writeToClientMessage(message: ClientMessage) { - message.putLongProperty(VERIFICATION_ID_FIELD_NAME, verificationId) - message.writeBodyBufferBytes(transaction.serialize().bytes) - MessageUtil.setJMSReplyTo(message, responseAddress) - } - } - - data class VerificationResponse( - val verificationId: Long, - val exception: Throwable? - ) { - companion object { - fun fromClientMessage(message: ClientMessage): VerificationResponse { - return VerificationResponse( - message.getLongProperty(VERIFICATION_ID_FIELD_NAME), - message.getBytesProperty(RESULT_EXCEPTION_FIELD_NAME)?.deserialize() - ) - } - } - - fun writeToClientMessage(message: ClientMessage, context: SerializationContext) { - message.putLongProperty(VERIFICATION_ID_FIELD_NAME, verificationId) - if (exception != null) { - message.putBytesProperty(RESULT_EXCEPTION_FIELD_NAME, exception.serialize(context = context).bytes) - } - } - } -} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 67dd12b541..00285e5c14 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -44,7 +44,6 @@ import net.corda.node.services.messaging.InternalRPCMessagingClient import net.corda.node.services.messaging.MessagingService import net.corda.node.services.messaging.P2PMessagingClient import net.corda.node.services.messaging.RPCServerConfiguration -import net.corda.node.services.messaging.VerifierMessagingClient import net.corda.node.services.rpc.ArtemisRpcBroker import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.utilities.AddressUtils @@ -125,10 +124,7 @@ open class Node(configuration: NodeConfiguration, } override val log: Logger get() = staticLog - override fun makeTransactionVerifierService(): TransactionVerifierService = when (configuration.verifierType) { - VerifierType.OutOfProcess -> throw IllegalArgumentException("OutOfProcess verifier not supported") //verifierMessagingClient!!.verifierService - VerifierType.InMemory -> InMemoryTransactionVerifierService(numberOfWorkers = 4) - } + override fun makeTransactionVerifierService(): TransactionVerifierService = InMemoryTransactionVerifierService(numberOfWorkers = 4) private val sameVmNodeNumber = sameVmNodeCounter.incrementAndGet() // Under normal (non-test execution) it will always be "1" @@ -212,10 +208,6 @@ open class Node(configuration: NodeConfiguration, printBasicNodeInfo("RPC connection address", it.primary.toString()) printBasicNodeInfo("RPC admin connection address", it.admin.toString()) } - verifierMessagingClient = when (configuration.verifierType) { - VerifierType.OutOfProcess -> throw IllegalArgumentException("OutOfProcess verifier not supported") //VerifierMessagingClient(configuration, serverAddress, services.monitoringService.metrics, /*networkParameters.maxMessageSize*/MAX_FILE_SIZE) - VerifierType.InMemory -> null - } require(info.legalIdentities.size in 1..2) { "Currently nodes must have a primary address and optionally one serviced address" } val serviceIdentity: PublicKey? = if (info.legalIdentities.size == 1) null else info.legalIdentities[1].owningKey return P2PMessagingClient( @@ -311,10 +303,6 @@ open class Node(configuration: NodeConfiguration, runOnStop += this::close init(rpcOps, securityManager) } - verifierMessagingClient?.run { - runOnStop += this::stop - start() - } (network as P2PMessagingClient).apply { runOnStop += this::stop start() @@ -414,11 +402,10 @@ open class Node(configuration: NodeConfiguration, } private var internalRpcMessagingClient: InternalRPCMessagingClient? = null - private var verifierMessagingClient: VerifierMessagingClient? = null + /** Starts a blocking event loop for message dispatch. */ fun run() { internalRpcMessagingClient?.start(rpcBroker!!.serverControl) - verifierMessagingClient?.start2() (network as P2PMessagingClient).run() } diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index ec8138eadf..46e889e06f 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -371,8 +371,7 @@ data class NodeH2Settings( ) enum class VerifierType { - InMemory, - OutOfProcess + InMemory } enum class CertChainPolicyType { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt deleted file mode 100644 index 4020542033..0000000000 --- a/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt +++ /dev/null @@ -1,74 +0,0 @@ -package net.corda.node.services.messaging - -import com.codahale.metrics.MetricRegistry -import net.corda.core.crypto.random63BitValue -import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.loggerFor -import net.corda.node.services.transactions.OutOfProcessTransactionVerifierService -import net.corda.node.utilities.AffinityExecutor -import net.corda.nodeapi.VerifierApi -import net.corda.nodeapi.VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME -import net.corda.nodeapi.VerifierApi.VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX -import net.corda.nodeapi.internal.ArtemisMessagingClient -import net.corda.nodeapi.internal.config.SSLConfiguration -import org.apache.activemq.artemis.api.core.RoutingType -import org.apache.activemq.artemis.api.core.SimpleString -import org.apache.activemq.artemis.api.core.client.ClientConsumer -import java.util.concurrent.TimeUnit - -class VerifierMessagingClient(config: SSLConfiguration, serverAddress: NetworkHostAndPort, metrics: MetricRegistry, private val maxMessageSize: Int) : SingletonSerializeAsToken() { - companion object { - private val log = loggerFor() - private val verifierResponseAddress = "$VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX.${random63BitValue()}" - } - - private val artemis = ArtemisMessagingClient(config, serverAddress, maxMessageSize) - /** An executor for sending messages */ - private val messagingExecutor = AffinityExecutor.ServiceAffinityExecutor("Messaging", 1) - private var verificationResponseConsumer: ClientConsumer? = null - fun start(): Unit = synchronized(this) { - val session = artemis.start().session - fun checkVerifierCount() { - if (session.queueQuery(SimpleString(VERIFICATION_REQUESTS_QUEUE_NAME)).consumerCount == 0) { - log.warn("No connected verifier listening on $VERIFICATION_REQUESTS_QUEUE_NAME!") - } - } - - // Attempts to create a durable queue on the broker which is bound to an address of the same name. - fun createQueueIfAbsent(queueName: String) { - val queueQuery = session.queueQuery(SimpleString(queueName)) - if (!queueQuery.isExists) { - log.info("Create fresh queue $queueName bound on same address") - session.createQueue(queueName, RoutingType.ANYCAST, queueName, true) - } - } - createQueueIfAbsent(VERIFICATION_REQUESTS_QUEUE_NAME) - createQueueIfAbsent(verifierResponseAddress) - verificationResponseConsumer = session.createConsumer(verifierResponseAddress) - messagingExecutor.scheduleAtFixedRate(::checkVerifierCount, 0, 10, TimeUnit.SECONDS) - } - - fun start2() = synchronized(this) { - verifierService.start(verificationResponseConsumer!!) - } - - fun stop() = synchronized(this) { - artemis.stop() - } - - internal val verifierService = OutOfProcessTransactionVerifierService(metrics) { nonce, transaction -> - messagingExecutor.fetchFrom { - sendRequest(nonce, transaction) - } - } - - private fun sendRequest(nonce: Long, transaction: LedgerTransaction) = synchronized(this) { - val started = artemis.started!! - val message = started.session.createMessage(false) - val request = VerifierApi.VerificationRequest(nonce, transaction, SimpleString(verifierResponseAddress)) - request.writeToClientMessage(message) - started.producer.send(VERIFICATION_REQUESTS_QUEUE_NAME, message) - } -} diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/OutOfProcessTransactionVerifierService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/OutOfProcessTransactionVerifierService.kt deleted file mode 100644 index 1a3350ae48..0000000000 --- a/node/src/main/kotlin/net/corda/node/services/transactions/OutOfProcessTransactionVerifierService.kt +++ /dev/null @@ -1,71 +0,0 @@ -package net.corda.node.services.transactions - -import com.codahale.metrics.Gauge -import com.codahale.metrics.MetricRegistry -import com.codahale.metrics.Timer -import net.corda.core.concurrent.CordaFuture -import net.corda.core.crypto.SecureHash -import net.corda.core.node.services.TransactionVerifierService -import net.corda.core.crypto.random63BitValue -import net.corda.core.internal.concurrent.OpenFuture -import net.corda.core.internal.concurrent.openFuture -import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.utilities.contextLogger -import net.corda.nodeapi.VerifierApi -import org.apache.activemq.artemis.api.core.client.ClientConsumer -import java.util.concurrent.ConcurrentHashMap - -class OutOfProcessTransactionVerifierService( - private val metrics: MetricRegistry, - private val sendRequest: (Long, LedgerTransaction) -> Unit -) : SingletonSerializeAsToken(), TransactionVerifierService { - companion object { - private val log = contextLogger() - } - - private data class VerificationHandle( - val transactionId: SecureHash, - val resultFuture: OpenFuture, - val durationTimerContext: Timer.Context - ) - - private val verificationHandles = ConcurrentHashMap() - - // Metrics - private fun metric(name: String) = "OutOfProcessTransactionVerifierService.$name" - - private val durationTimer = metrics.timer(metric("Verification.Duration")) - private val successMeter = metrics.meter(metric("Verification.Success")) - private val failureMeter = metrics.meter(metric("Verification.Failure")) - - class VerificationResultForUnknownTransaction(nonce: Long) : - Exception("Verification result arrived for unknown transaction nonce $nonce") - - fun start(responseConsumer: ClientConsumer) { - log.info("Starting out of process verification service") - metrics.register(metric("VerificationsInFlight"), Gauge { verificationHandles.size }) - responseConsumer.setMessageHandler { message -> - val response = VerifierApi.VerificationResponse.fromClientMessage(message) - val handle = verificationHandles.remove(response.verificationId) ?: throw VerificationResultForUnknownTransaction(response.verificationId) - handle.durationTimerContext.stop() - val exception = response.exception - if (exception == null) { - successMeter.mark() - handle.resultFuture.set(Unit) - } else { - failureMeter.mark() - handle.resultFuture.setException(exception) - } - } - } - - override fun verify(transaction: LedgerTransaction): CordaFuture<*> { - log.info("Verifying ${transaction.id}") - val future = openFuture() - val nonce = random63BitValue() - verificationHandles[nonce] = VerificationHandle(transaction.id, future, durationTimer.time()) - sendRequest(nonce, transaction) - return future - } -} \ No newline at end of file diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/DriverDSL.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/DriverDSL.kt index 9606dcb96c..996d902ce0 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/DriverDSL.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/DriverDSL.kt @@ -11,8 +11,7 @@ import net.corda.testing.node.NotarySpec import java.nio.file.Path enum class VerifierType { - InMemory, - OutOfProcess + InMemory } /** From 21d06a8aa9620fd619d9c87394ffe3f49b74bd05 Mon Sep 17 00:00:00 2001 From: Viktor Kolomeyko Date: Mon, 25 Jun 2018 14:13:21 +0100 Subject: [PATCH 3/5] ENT-2132 Introduce a boolean flag which controls whether we should re-try RPC connection. (#3433) In case of initial logon - it will not be re-tried to cater for invalid endpoint and/or credentials. However, if connection been successfully established once, re-try logic is getting activated. --- .../client/jfx/model/NodeMonitorModel.kt | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NodeMonitorModel.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NodeMonitorModel.kt index 0194edb110..ec66c85988 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NodeMonitorModel.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NodeMonitorModel.kt @@ -6,7 +6,6 @@ import javafx.beans.property.SimpleObjectProperty import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.CordaRPCClientConfiguration import net.corda.client.rpc.CordaRPCConnection -import net.corda.client.rpc.RPCException import net.corda.core.contracts.ContractState import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.Party @@ -22,7 +21,6 @@ import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger import net.corda.core.utilities.seconds -import org.apache.activemq.artemis.api.core.ActiveMQException import rx.Observable import rx.Subscription import rx.subjects.PublishSubject @@ -125,7 +123,7 @@ class NodeMonitorModel { } } - val stateMachines = performRpcReconnect(nodeHostAndPort, username, password) + val stateMachines = performRpcReconnect(nodeHostAndPort, username, password, shouldRetry = false) // Extract the flow tracking stream // TODO is there a nicer way of doing this? Stream of streams in general results in code like this... @@ -146,9 +144,9 @@ class NodeMonitorModel { futureProgressTrackerUpdates.startWith(currentProgressTrackerUpdates).flatMap { it }.retry().subscribe(progressTrackingSubject) } - private fun performRpcReconnect(nodeHostAndPort: NetworkHostAndPort, username: String, password: String): List { + private fun performRpcReconnect(nodeHostAndPort: NetworkHostAndPort, username: String, password: String, shouldRetry: Boolean): List { - val connection = establishConnectionWithRetry(nodeHostAndPort, username, password) + val connection = establishConnectionWithRetry(nodeHostAndPort, username, password, shouldRetry) val proxy = connection.proxy val (stateMachineInfos, stateMachineUpdatesRaw) = proxy.stateMachinesFeed() @@ -166,7 +164,7 @@ class NodeMonitorModel { // force closing the connection to avoid propagation of notification to the server side. connection.forceClose() // Perform re-connect. - performRpcReconnect(nodeHostAndPort, username, password) + performRpcReconnect(nodeHostAndPort, username, password, shouldRetry = true) }) retryableStateMachineUpdatesSubscription.set(subscription) @@ -176,7 +174,7 @@ class NodeMonitorModel { return stateMachineInfos } - private fun establishConnectionWithRetry(nodeHostAndPort: NetworkHostAndPort, username: String, password: String): CordaRPCConnection { + private fun establishConnectionWithRetry(nodeHostAndPort: NetworkHostAndPort, username: String, password: String, shouldRetry: Boolean): CordaRPCConnection { val retryInterval = 5.seconds @@ -195,21 +193,15 @@ class NodeMonitorModel { require(nodeInfo.legalIdentitiesAndCerts.isNotEmpty()) _connection } catch (throwable: Throwable) { - when (throwable) { - is ActiveMQException, is RPCException -> { - // Happens when: - // * incorrect credentials provided; - // * incorrect endpoint specified; - // - no point to retry connecting. - throw throwable - } - else -> { - // Deliberately not logging full stack trace as it will be full of internal stacktraces. - logger.info("Exception upon establishing connection: " + throwable.message) - null - } + if (shouldRetry) { + // Deliberately not logging full stack trace as it will be full of internal stacktraces. + logger.info("Exception upon establishing connection: " + throwable.message) + null + } else { + throw throwable } } + if (connection != null) { logger.info("Connection successfully established with: $nodeHostAndPort") return connection From 868763f82bc85ac517607435931de103159fc822 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Mon, 25 Jun 2018 15:15:52 +0100 Subject: [PATCH 4/5] Fix for running tests from Idea (#3425) --- .../kotlin/net/corda/node/internal/cordapp/CordappLoader.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt index 288eb74ddc..b213a0fb9e 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt @@ -135,7 +135,9 @@ class CordappLoader private constructor(private val cordappJarPaths: List listOf("main", "production").none { url.toString().contains("$it/$resource") } || listOf("net.corda.core", "net.corda.node", "net.corda.finance").none { scanPackage.startsWith(it) } } + .filter { url -> + !url.toString().contains("main/$resource") || listOf("net.corda.core", "net.corda.node", "net.corda.finance").none { scanPackage.startsWith(it) } + } .map { url -> if (url.protocol == "jar") { // When running tests from gradle this may be a corda module jar, so restrict to scanPackage: From e00c7706c3f52d0e338f83d169e60c99d623f1c5 Mon Sep 17 00:00:00 2001 From: Michal Kit Date: Mon, 25 Jun 2018 16:40:51 +0100 Subject: [PATCH 5/5] CORDA-1661 Reverting DEV certificates (#3422) * CORDA-1661 Reverting DEV certificates * Addressing review comments * Removed the intermediate certificate from the trust store and added some test cases for the revocation check --- .../resources/certificates/cordadevcakeys.jks | Bin 2447 -> 2294 bytes .../certificates/cordatruststore.jks | Bin 665 -> 593 bytes .../internal/crypto/DevCertificatesTest.kt | 41 +++++++++++++ .../regression-test/nodekeystore.jks | Bin 0 -> 1980 bytes .../resources/regression-test/sslkeystore.jks | Bin 0 -> 2472 bytes .../CertificateRevocationListNodeTests.kt | 57 +++++++++++++++++- .../internal/amqp/SerializationOutputTests.kt | 17 +++--- 7 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/DevCertificatesTest.kt create mode 100644 node-api/src/test/resources/regression-test/nodekeystore.jks create mode 100644 node-api/src/test/resources/regression-test/sslkeystore.jks diff --git a/node-api/src/main/resources/certificates/cordadevcakeys.jks b/node-api/src/main/resources/certificates/cordadevcakeys.jks index ec72cb50819cfa663ea66e74a020dd1d48cdbc1b..83ab6bb01f44c7f5de4681659d4087bc1b4c366d 100644 GIT binary patch literal 2294 zcmezO_TO6u1_mZ5W@Hdf&M!(y%*-oEEy_(z$xJLsO-^KBU`){vlspGibj6_Yq5&Tp zmo^(C3!@g3AR{9y154vR`3o_h568H)%cf+!`pA9P!{h4J+5>v7vxU`-cTMT+{O@e= zU;4toH)-mQ7iyMUyn7&hXU-zAYtQ7q+}(Ne-+5MtxTLU_UvrfARvu8fWN+`G;9$YI z$HjR`*QVH>_lp*<<2^rl%{zs^xz~>TSSV$iY0z5pKza4c4K)iV-O@Vv{7|#jJaJFG ztcfNZTNU2jnx{3jVJeob?PdM$?v435uE-$)qg5^0rQ=XF<8T(kb zONkw7*%I^k64>*s5qhQumcXD`Y0$*96o?%cFf%bSF>&}!*c$ZmgRr!L2pfl1o5wj@ z7G@?Wik?kYj{-gNzkC@^ez0^A&u2oDC%n z#6jZB!U7NAATpiIEXxFr$GBNRK>=t%0?H{b|@+-UC z@UI)QlIZ)T`=Yex&%15K08g{L!1T&#(8Ra_nq~{ax2!y!<@MZv3z24NoKita6IV*5 zT^_-mJTuc?Y;<26XKRWdAMmf*fNPC^&FF+#|JkhjGx-I?a`>JWL82t1f#uXO;YnK6Y7ep|wQgx@F=2 ztq(A;MTM>Pu-c`{2rSPS8Mwhk3@90b3-B0&t0@w=3vl*bG7k-_^-U#1_=<#WksNxsoi^xh4@uEF3wKU!B-@!od%xx9g+tS)=2omMx8gf;%>So&z?`^* zxQ%SWfdMD;C4btS&UJ-XhB6aGf5ao(0 zi~TiKbILDUG**50R(G|WHCz4jkFDRY8lh)uUwwsE0W%XL6B9?>-n7%5fh*PJwRxPg zWnpH5vX~j!4H68w4LI4DLs{5_nL>jN1r7K?9Cl$2ztnPt$o!&gLp}o@kPx>pt1~EU z4aI;a0r_0Qyg|ka9{D*b&iM*HKF%<4W?^2iI)$M8{1OFcM*}%=UPB85GectoFo+W8 zH3D%VJcB5MWU9G9(m)*KGG<``hznfu^NVs5^FWS>G!SNE2Ya815#f7gCk7VlNb#Lh zjW=&rd??YxewMFB#HdmAcJqQGB}EmzuhJIIX1ec^c1AmV!@H6Y8`;)}iObIk&bX_> z6};T+R^plIDNc(U?;AAUF^~n?EX&6t#v(F--_63Z-e2nS<6A$QPM*m$e%j*%4pmuU zM#ldvtOm?L%77cBo}UF68H{ZP${>y^i;RI38wW6Hva+%>16>JaF|n}#B^eClL5h@F zBn-qFL}orWn6hea1XHERj*96j-Ph$Zxf%=vq3OE0D~XX2WH6(F3rLSVi>-mRf#m}8 z1*UDr86_nJR{Huy#=0e`#U*;l`MLVZsYNB3X_?8u%%WSAT9yxFWaj7T=42L^=obMa z5qrvE_GB<{V^U<8yXO6(@@^Ny+*XP2m3ugshVRY{s}~Euxgl+XkGIk7XFw(EbQWuF zk*t}axp<;PxK)j{vV2X(9^sl7<%xSrW;U$gV}K{#P+-ChG-zUc3r)NgcdxH3-X^gE zyAuXM;-!7|!JTru95e$M6opfi0usM3czDaoSJV2lcFhqn=M^r=d|nakBD43{W<{=j zb^Okf4#8lpoqF?)er*$adH%Y{qa|t+G}IS2wiz@wBc)udsR~pc&^qN}Et;4;7z|v2 zsi*DAw{60bE#+bx;*0X$iwAXRer;H6v!qkTGI!&&N8Hg&3h5WWc$j~kcwn`$hlQ`w z?p>cXl{j~Hx1CQbZBfS5ak}>hmdfv80^{u;i zZgN~E6Mw@u!RKabcB63k*>B%Y%FnMq=a9Yoh;lcZ#g*+#s)YB&yq_ul^Gww4UDx{5 zZ>Ma1t5#bgr)pKfA#=Z+t9nZi`}dWt7kYYFcn&Zf_uyDIBW0=BUnlMhe|}m%2vOs@ z@9<@=%7M>rfya_&nn!nSxinjPm%;kLIU#NFy82eqd^pcw4o(M*NAP8!Wr6lbb;ab{_yG98Um QqK&6aESs)yedR?50R30tO8@`> diff --git a/node-api/src/main/resources/certificates/cordatruststore.jks b/node-api/src/main/resources/certificates/cordatruststore.jks index 97b4aebe18239235ed78e1ec023973e5d2826ede..47528654e026b8a0aa0d2424195be92cdc4ac9b8 100644 GIT binary patch literal 593 zcmezO_TO6u1_mY|W(3pR$@xVoiADMOCCQ0Eu^5A^DKZSK5qhQumOy2^22D(y22G3` z7BDk0GBI%!gl}1SI?L<10T&yGR-4B;TNY*}g9t-u14%aKP!?t$A!m?j3V!)1sR}_r zGZma24Y>_CL6TfNOhLwmdb($jAT;qQrTPKwJpVAc}@IM;ZvTv4efc#0d2&Gb1~*69Y?T+KY|uYa@;8p0an< z{!-hyHPcyYZT;E6sUJSoD|jiTZJhixz$;b#`Tyx=K9luaQog+9JkfT)E8XI+T*vWx zRfEMT21y38Ku^o^v52vV)T~>1f2Rkdws0r+tY@yRGM3`(#Rl9UX?_-9;4-!uD1$hv zEHVaCY#iEbjI6Be%s?kWSxjs!KuHDzevl$zM#ldvtOm?L3ORz9-5CsAm=t&y{qW-M z+Hifc|CV_{j9*!q$3N?NVhtyPbWloVYO?A6KZ{zNxWxJxmO50U#`zIsgCw literal 665 zcmezO_TO6u1_mY|W(3pR$@xVoiADMOCCQ0EvE(1MY@7_N5qhQumOy2p22D(X22G4_ z7cet1GBI&f+`YcCc$>ru0}(b3tu~Kywk*s{P!=;IyFr2>w*e;`b0`a&FjHu-p`Zaj zh{G<-;g?#j5Sd?;ZOCW90}|pEW_1SHYbXXZ3CQOX<_$7d@W{_ean4up@o|QUGYj*A z)hPr49jM^!XdoxfYiMC$W@u~x22tX?Mj$SPXAngP7epEev$2Ey&culDI7kRWqZGwjS;>I?E#%2RqV1UT-v52vV%zSPzW!2mWrb>|=71LF^ughg}HGqRu zR+y3TKMSh?GmtXi2C3&~0mcMln}ITjqsk&U Ketzln&m;gds)w@`i^zAe!Wx07p>Xc_+W!~>dBSY*Q7lZ(=nf= z=c{+~KGWjHg9eTJ3}k^e%JQ*@v4}|C*rX}3bV>JDf7W0P=@ob1D1GJwJ4jZTk?}tZ zs{u2RGT;WO=Vt*1En}O3GKizfB4Z%M#sN%dtgP(JKvzOpOl&MbNd^N!Xd-OxN@8RL z>0>c)2kDaonQCiby#N?SON_|~oP`Y7W188M!N844kzvvK3FmkW%*-{2c2X}yPmN^ad3D}JMCbmH>XU(*`4N%V$vx*g_x`p_pY;fxBCY6CYS zv55i`n;jH>U6mXH098E_#In?Z!3w1FhhZ@?rbgp|aB^7BimkhDN)37VKN zk{0a~H|~_keEQx3wTEeGo2M(WMj0Bi-q+qec}7X--t=qEPec>`-Zm&%u%j&SjO_b2 z&MhCsG9}EG|K>G$Tk$(q*6v7t(6NNYDF#VM>G1VCJp)lqhjo%O@T1=Yu4D&@N@-P8XSJFE+ZbjWn)%%HCD`OKs=YOlPUJ^=AX8e)v?c;H8wdaq`mu zuT=Ht|EHVzOxANr`SO&AOHMcX}{t3wLtQdgj_HV=2yF zOq+DUyXc1(ch`pNll`~M3v!HIpy0syaF5jD9mYXR>oixk@-QiAth(&soK^BO`q*W? uh1L>{>z0N8w?4qY78SPE!)li*qu+uBQzBfp{mf>%S9UDMuF~)D{!ajZayL-` literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/regression-test/sslkeystore.jks b/node-api/src/test/resources/regression-test/sslkeystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..60288cb5f70aa858c9ad3a13b441294fa5b7c10d GIT binary patch literal 2472 zcmezO_TO6u1_mY|W&~rtX_7 zT1Yj9 zmduzQy=8CktLXh2GbY9d@4tNUa(|%90jJYZ{-@TSjP&BpC}{84fB8YNsp*q!2P>@^ zIa_$z@0s23N%(wyxg`6V+2JPl*7Qi`{fc$D*|~51#pKW%njg<^c=h6-&%D@No9TD{ zEc_Bw%jL`#woM}QWBZ%rmb&IL{bL;psn5ioSnRp-Z>>h_o+`#W-+DN+{_yfYik!oo za{UF+Un~r)5qhQumO!sQFlb`D1H_dJn3))vm^geH?kmmu<#5M9gpEV1&EuRc3o{dx z#mvZVU}(r~z{$oO%EBhh%Uu=B9_S3a`V|HR-(WpMikidBLSY|En zKW^CtiKnh|E1UmMpIz-Rb1K`CpJ%^x7`gHE9GcIkEt- z1sF!mD-4uD990$>11UBRV2WX7WoHJu4$5L;V*yGs7zjdBQ*&1mBO_2BBP;fhW_D*V zaA8tVZGAA$iAz0b?QOOorDCN5`KR(4upcYr~Hp|XJ@ zC^DIOq<|5blBnR9pOUKJnOBlpl$)B8nOKsl;Oq!X4_rJCs^7@*zhhjSBv-EuRZr*2F+<4HSaUW9Jki4-;Q)20o?yvr=!5Y#l?!Hm_ z%m+^Wvcimv|5;cKn1K{h3Sn#`Glj4ixPwxb9LQ8#1M3CA+_S`(jBK-z0eeg{domcf zF)1=EIzQnYkAZwfyw$Czdgbi%TD~Qg9=Gq>+3p*B!z8WuFi^>@`(nj!G>uMN-ui1= z!#0WDkWRP5oKGM6-U}6&lCbk{W#FkO@J<;;9|1kqDM7d%RVJK}N z2}xo?NJ%UxKfi`-Zm&%u%j&SjO_b2&MhCsG9}EG|K>G$Tk$(q*6v7t(6NNYDF#VM>G1VC zJp)lqhjo%O{W>ZN;u1VK-tMF7H`C zVFt&})10iu_dLFSKAp*=pm2V<$rZ~Bceq~1D&F0={cXXvE!q2+H$2>ScfzBBSG#Kw z>4O)TJ~)BtV*@mO6ohYCc{mZ|LJBvll5FuzP#l;(RRNp-QurY$MJeq1GIEevu@@6 zogR$Z!kyf+p1HQlScKRWdAMmf*fNPC^&FF+#|JkhjGx-I?a`> zJWL82t1f#uXO;YnK6Y7ep|wQgx@F=2tq(A;MTM>Pu-c`{xOLv0PL?O3-5TeMRv-Iu KWXCTBOM3vVy1Y98 literal 0 HcmV?d00001 diff --git a/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt b/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt index 4e709fd91c..10e9c2c6d9 100644 --- a/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/amqp/CertificateRevocationListNodeTests.kt @@ -94,7 +94,7 @@ class CertificateRevocationListNodeTests { } @Test - fun `Simple AMPQ Client to Server connection works`() { + fun `Simple AMPQ Client to Server connection works and soft fail is enabled`() { val crlCheckSoftFail = true val (amqpServer, _) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail) amqpServer.use { @@ -126,7 +126,39 @@ class CertificateRevocationListNodeTests { } @Test - fun `AMPQ Client to Server connection fails when client's certificate is revoked`() { + fun `Simple AMPQ Client to Server connection works and soft fail is disabled`() { + val crlCheckSoftFail = false + val (amqpServer, _) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail) + amqpServer.use { + amqpServer.start() + val receiveSubs = amqpServer.onReceive.subscribe { + assertEquals(BOB_NAME.toString(), it.sourceLegalName) + assertEquals(P2P_PREFIX + "Test", it.topic) + assertEquals("Test", String(it.payload)) + it.complete(true) + } + val (amqpClient, _) = createClient(serverPort, crlCheckSoftFail) + amqpClient.use { + val serverConnected = amqpServer.onConnection.toFuture() + val clientConnected = amqpClient.onConnection.toFuture() + amqpClient.start() + val serverConnect = serverConnected.get() + assertEquals(true, serverConnect.connected) + val clientConnect = clientConnected.get() + assertEquals(true, clientConnect.connected) + val msg = amqpClient.createMessage("Test".toByteArray(), + P2P_PREFIX + "Test", + ALICE_NAME.toString(), + emptyMap()) + amqpClient.write(msg) + assertEquals(MessageStatus.Acknowledged, msg.onComplete.get()) + receiveSubs.unsubscribe() + } + } + } + + @Test + fun `AMPQ Client to Server connection fails when client's certificate is revoked and soft fail is enabled`() { val crlCheckSoftFail = true val (amqpServer, _) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail) amqpServer.use { @@ -146,6 +178,27 @@ class CertificateRevocationListNodeTests { } } + @Test + fun `AMPQ Client to Server connection fails when client's certificate is revoked and soft fail is disabled`() { + val crlCheckSoftFail = false + val (amqpServer, _) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail) + amqpServer.use { + amqpServer.start() + amqpServer.onReceive.subscribe { + it.complete(true) + } + val (amqpClient, clientCert) = createClient(serverPort, crlCheckSoftFail) + revokedNodeCerts.add(clientCert.serialNumber) + amqpClient.use { + val serverConnected = amqpServer.onConnection.toFuture() + amqpClient.onConnection.toFuture() + amqpClient.start() + val serverConnect = serverConnected.get() + assertEquals(false, serverConnect.connected) + } + } + } + @Test fun `AMPQ Client to Server connection fails when servers's certificate is revoked`() { val crlCheckSoftFail = true diff --git a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt index cab56596d1..a4b73fb283 100644 --- a/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt +++ b/serialization/src/test/kotlin/net/corda/serialization/internal/amqp/SerializationOutputTests.kt @@ -15,12 +15,10 @@ import net.corda.core.flows.FlowException import net.corda.core.identity.AbstractParty import net.corda.core.identity.CordaX500Name import net.corda.core.internal.AbstractAttachment -import net.corda.core.internal.x500Name import net.corda.core.serialization.* import net.corda.core.transactions.LedgerTransaction import net.corda.core.utilities.OpaqueBytes import net.corda.node.serialization.amqp.AMQPServerSerializationScheme -import net.corda.nodeapi.internal.DEV_INTERMEDIATE_CA import net.corda.nodeapi.internal.crypto.ContentSignerBuilder import net.corda.serialization.internal.* import net.corda.serialization.internal.amqp.SerializerFactory.Companion.isPrimitive @@ -35,6 +33,7 @@ import org.apache.qpid.proton.amqp.* import org.apache.qpid.proton.codec.DecoderImpl import org.apache.qpid.proton.codec.EncoderImpl import org.assertj.core.api.Assertions.* +import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509v2CRLBuilder import org.bouncycastle.cert.jcajce.JcaX509CRLConverter import org.bouncycastle.jce.provider.BouncyCastleProvider @@ -657,8 +656,8 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi val scheme = AMQPServerSerializationScheme(emptyList()) val func = scheme::class.superclasses.single { it.simpleName == "AbstractAMQPSerializationScheme" } .java.getDeclaredMethod("registerCustomSerializers", - SerializationContext::class.java, - SerializerFactory::class.java) + SerializationContext::class.java, + SerializerFactory::class.java) func.isAccessible = true val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) @@ -1011,7 +1010,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi } private fun emptyCrl(): X509CRL { - val builder = X509v2CRLBuilder(CordaX500Name.build(DEV_INTERMEDIATE_CA.certificate.issuerX500Principal).x500Name, Date()) + val builder = X509v2CRLBuilder(X500Name("CN=Corda Root CA, O=R3 HoldCo LLC, L=New York, C=US"), Date()) val provider = BouncyCastleProvider() val crlHolder = builder.build(ContentSignerBuilder.build(Crypto.RSA_SHA256, Crypto.generateKeyPair(Crypto.RSA_SHA256).private, provider)) return JcaX509CRLConverter().setProvider(provider).getCRL(crlHolder) @@ -1320,12 +1319,12 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi } interface DataClassByInterface { - val v : V + val v: V } @Test fun dataClassBy() { - data class C (val s: String) : DataClassByInterface { + data class C(val s: String) : DataClassByInterface { override val v: String = "-- $s" } @@ -1339,8 +1338,8 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi try { val i2 = DeserializationInput(testDefaultFactory()).deserialize(bytes) - } catch (e : NotSerializableException) { - throw Error ("Deserializing serialized \$C should not throw") + } catch (e: NotSerializableException) { + throw Error("Deserializing serialized \$C should not throw") } } }