From cd038ea107f4f7d58b01e7e1bbd768d1213e95f8 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Tue, 20 Mar 2018 11:42:48 +0000 Subject: [PATCH 1/4] Fixed docsite on incorrect node config filename required for bootstrapping a local network. (#2848) --- docs/source/setting-up-a-corda-network.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/source/setting-up-a-corda-network.rst b/docs/source/setting-up-a-corda-network.rst index 0b48c7dd9e..9d6ba6c7f5 100644 --- a/docs/source/setting-up-a-corda-network.rst +++ b/docs/source/setting-up-a-corda-network.rst @@ -61,9 +61,11 @@ be done with the network bootstrapper. This is a tool that scans all the node co generate the network parameters file which is copied to the nodes' directories. It also copies each node's node-info file to every other node so that they can all transact with each other. -The bootstrapper tool can be downloaded from http://downloads.corda.net/network-bootstrapper-corda-X.Y.jar, where ``X`` is the major Corda version and ``Y`` is the minor Corda version. +The bootstrapper tool can be downloaded from http://downloads.corda.net/network-bootstrapper-corda-X.Y.jar, where ``X`` +is the major Corda version and ``Y`` is the minor Corda version. -To use it, create a directory containing a ``node.conf`` file for each node you want to create. Then run the following command: +To use it, create a directory containing a node config file, ending in "_node.conf", for each node you want to create. +Then run the following command: ``java -jar network-bootstrapper.jar `` @@ -72,9 +74,9 @@ For example running the command on a directory containing these files : .. sourcecode:: none . - ├── notary.conf // The notary's node.conf file - ├── partya.conf // Party A's node.conf file - └── partyb.conf // Party B's node.conf file + ├── notary_node.conf // The notary's node.conf file + ├── partya_node.conf // Party A's node.conf file + └── partyb_node.conf // Party B's node.conf file Would generate directories containing three nodes: notary, partya and partyb. From 182294913a3976924043084d0b36a2bc78dbffe5 Mon Sep 17 00:00:00 2001 From: szymonsztuka Date: Tue, 20 Mar 2018 12:53:41 +0000 Subject: [PATCH 2/4] CORDA-2615: Added description for configFile option in deployNodes Cordform Gradle task. (#2825) --- docs/source/generating-a-node.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/source/generating-a-node.rst b/docs/source/generating-a-node.rst index 6c9d901235..3625692701 100644 --- a/docs/source/generating-a-node.rst +++ b/docs/source/generating-a-node.rst @@ -152,6 +152,24 @@ You can extend ``deployNodes`` to generate additional nodes. .. warning:: When adding nodes, make sure that there are no port clashes! +To extend node configuration beyond the properties defined in the ``deployNodes`` task use the ``configFile`` property with the path (relative or absolute) set to an additional configuration file. +This file should follow the standard :doc:`corda-configuration-file` format, as per node.conf. The properties from this file will be appended to the generated node configuration. Note, if you add a property already created by the 'deployNodes' task, both properties will be present in the file. +The path to the file can also be added while running the Gradle task via the ``-PconfigFile`` command line option. However, the same file will be applied to all nodes. +Following the previous example ``PartyB`` node will have additional configuration options added from a file ``none-b.conf``: + +.. sourcecode:: groovy + + task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { + [...] + node { + name "O=PartyB,L=New York,C=US" + [...] + // Grants user1 the ability to start the MyFlow flow. + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["StartFlow.net.corda.flows.MyFlow"]]] + configFile = "samples/trader-demo/src/main/resources/none-b.conf" + } + } + Specifying a custom webserver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, any node listing a webport will use the default development webserver, which is not production-ready. You From 144632818c106425c55767b9e12a381464c9d24e Mon Sep 17 00:00:00 2001 From: Michal Kit Date: Tue, 20 Mar 2018 15:42:25 +0000 Subject: [PATCH 3/4] Adding the X509CRL custom serializer. (#2844) CORDA-1233 * Adding the X509CRL custom serializer. * Addressing review comments --- docs/source/changelog.rst | 2 ++ .../amqp/AMQPSerializationScheme.kt | 1 + .../amqp/custom/X509CRLSerializer.kt | 27 +++++++++++++++ .../amqp/SerializationOutputTests.kt | 33 ++++++++++++++++++- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/X509CRLSerializer.kt diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 167df1cddc..9c48115b0f 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -19,6 +19,8 @@ from the previous milestone release. * java.security.cert.CRLReason added to the default Whitelist. +* java.security.cert.X509CRL serialization support added. + .. _changelog_v3: Version 3.0 diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt index b56cbea372..96d01fa287 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt @@ -71,6 +71,7 @@ abstract class AbstractAMQPSerializationScheme(val cordappLoader: List) register(net.corda.nodeapi.internal.serialization.amqp.custom.PeriodSerializer(this)) register(net.corda.nodeapi.internal.serialization.amqp.custom.ClassSerializer(this)) register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CRLSerializer) register(net.corda.nodeapi.internal.serialization.amqp.custom.CertPathSerializer(this)) register(net.corda.nodeapi.internal.serialization.amqp.custom.StringBufferSerializer) register(net.corda.nodeapi.internal.serialization.amqp.custom.SimpleStringSerializer) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/X509CRLSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/X509CRLSerializer.kt new file mode 100644 index 0000000000..2f98bddb74 --- /dev/null +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/X509CRLSerializer.kt @@ -0,0 +1,27 @@ +package net.corda.nodeapi.internal.serialization.amqp.custom + +import net.corda.nodeapi.internal.crypto.X509CertificateFactory +import net.corda.nodeapi.internal.serialization.amqp.* +import org.apache.qpid.proton.codec.Data +import java.lang.reflect.Type +import java.security.cert.X509CRL + +object X509CRLSerializer : CustomSerializer.Implements(X509CRL::class.java) { + override val schemaForDocumentation = Schema(listOf(RestrictedType( + type.toString(), + "", + listOf(type.toString()), + SerializerFactory.primitiveTypeName(ByteArray::class.java)!!, + descriptor, + emptyList() + ))) + + override fun writeDescribedObject(obj: X509CRL, data: Data, type: Type, output: SerializationOutput) { + output.writeObject(obj.encoded, data, clazz) + } + + override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): X509CRL { + val bytes = input.readObject(obj, schemas, ByteArray::class.java) as ByteArray + return X509CertificateFactory().delegate.generateCRL(bytes.inputStream()) as X509CRL + } +} \ No newline at end of file diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt index bf081d04ad..9f2921e8f3 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt @@ -8,15 +8,19 @@ import net.corda.client.rpc.RPCException import net.corda.core.CordaException import net.corda.core.CordaRuntimeException import net.corda.core.contracts.* +import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash import net.corda.core.crypto.secureRandomBytes 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.nodeapi.internal.DEV_INTERMEDIATE_CA +import net.corda.nodeapi.internal.crypto.ContentSignerBuilder import net.corda.nodeapi.internal.serialization.* import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive import net.corda.testing.contracts.DummyContract @@ -29,6 +33,9 @@ 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.cert.X509v2CRLBuilder +import org.bouncycastle.cert.jcajce.JcaX509CRLConverter +import org.bouncycastle.jce.provider.BouncyCastleProvider import org.junit.Assert.* import org.junit.Ignore import org.junit.Rule @@ -41,6 +48,7 @@ import java.io.IOException import java.io.NotSerializableException import java.math.BigDecimal import java.math.BigInteger +import java.security.cert.X509CRL import java.time.* import java.time.temporal.ChronoUnit import java.util.* @@ -51,6 +59,7 @@ import kotlin.test.assertTrue object AckWrapper { object Ack + fun serialize() { val factory = testDefaultFactoryNoEvolution() SerializationOutput(factory).serialize(Ack) @@ -59,6 +68,7 @@ object AckWrapper { object PrivateAckWrapper { private object Ack + fun serialize() { val factory = testDefaultFactoryNoEvolution() SerializationOutput(factory).serialize(Ack) @@ -630,6 +640,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi } private val FOO_PROGRAM_ID = "net.corda.nodeapi.internal.serialization.amqp.SerializationOutputTests.FooContract" + class FooState : ContractState { override val participants: List = emptyList() } @@ -992,6 +1003,25 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi assertEquals(objCopy.a, objCopy.b) } + private fun emptyCrl(): X509CRL { + val builder = X509v2CRLBuilder(CordaX500Name.build(DEV_INTERMEDIATE_CA.certificate.issuerX500Principal).x500Name, 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) + } + + @Test + fun `test X509CRL custom serializer`() { + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CRLSerializer) + + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CRLSerializer) + + val obj = emptyCrl() + serdes(obj, factory, factory2) + } + data class ByteArrays(val a: ByteArray, val b: ByteArray) @Test @@ -1197,7 +1227,8 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi @Test fun throwable() { class TestException(message: String?, cause: Throwable?) : CordaException(message, cause) - val testExcp = TestException("hello", Throwable().apply { stackTrace = Thread.currentThread().stackTrace } ) + + val testExcp = TestException("hello", Throwable().apply { stackTrace = Thread.currentThread().stackTrace }) val factory = testDefaultFactoryNoEvolution() SerializationOutput(factory).serialize(testExcp) From ac9cb59a6eacfc45c592ece290c79f3fd7c3f9f8 Mon Sep 17 00:00:00 2001 From: bpaunescu Date: Tue, 20 Mar 2018 16:23:29 +0000 Subject: [PATCH 4/4] Fix RPC flaky test (#2849) * fix rpc reconnect flaky test; remove obsolete rpcproxy log message * rpc client proxy: replace lock with atomic variable * rpc client proxy: removed volatile property * RPCStabilityTests: used eventually() method to test async response * RPCStabilityTests: remove unused import --- client/rpc/build.gradle | 1 + .../net/corda/client/rpc/RPCStabilityTests.kt | 6 ++--- .../rpc/internal/RPCClientProxyHandler.kt | 22 +++++-------------- node-api/build.gradle | 13 +++++++++++ 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/client/rpc/build.gradle b/client/rpc/build.gradle index d60a6eb8d5..72c6f41ed5 100644 --- a/client/rpc/build.gradle +++ b/client/rpc/build.gradle @@ -78,6 +78,7 @@ dependencies { testCompile project(':node-driver') testCompile project(':client:mock') + integrationTestCompile project(path: ':node-api', configuration: 'testArtifacts') // Smoke tests do NOT have any Node code on the classpath! smokeTestCompile project(':smoke-test-utils') diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt index 8dcb6e3858..99cfc38e2a 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCStabilityTests.kt @@ -12,6 +12,7 @@ import net.corda.core.serialization.serialize import net.corda.core.utilities.* import net.corda.node.services.messaging.RPCServerConfiguration import net.corda.nodeapi.RPCApi +import net.corda.nodeapi.eventually import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.internal.testThreadFactory import net.corda.testing.node.internal.* @@ -247,9 +248,8 @@ class RPCStabilityTests { assertEquals("pong", client.ping()) serverFollower.shutdown() startRpcServer(ops = ops, customPort = serverPort).getOrThrow() - Thread.sleep(1000) //wait for the server to come back up - val pingFuture = pool.fork(client::ping) - assertEquals("pong", pingFuture.getOrThrow(10.seconds)) + val response = eventually(10.seconds) { client.ping() } + assertEquals("pong", response) clientFollower.shutdown() // Driver would do this after the new server, causing hang. } } diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt index aa93a48c3c..dc07b1ada2 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt @@ -41,10 +41,9 @@ import java.lang.reflect.Method import java.time.Instant import java.util.* import java.util.concurrent.* +import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicLong -import java.util.concurrent.locks.ReentrantReadWriteLock -import kotlin.concurrent.withLock import kotlin.reflect.jvm.javaMethod /** @@ -173,9 +172,7 @@ class RPCClientProxyHandler( private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry) private val deduplicationSequenceNumber = AtomicLong(0) - private val lock = ReentrantReadWriteLock() - @Volatile - private var sendingEnabled = true + private val sendingEnabled = AtomicBoolean(true) /** * Start the client. This creates the per-client queue, starts the consumer session and the reaper. @@ -219,10 +216,8 @@ class RPCClientProxyHandler( throw RPCException("RPC Proxy is closed") } - lock.readLock().withLock { - if (!sendingEnabled) - throw RPCException("RPC server is not available.") - } + if (!sendingEnabled.get()) + throw RPCException("RPC server is not available.") val replyId = InvocationId.newInstance() callSiteMap?.set(replyId, Throwable("")) @@ -411,11 +406,8 @@ class RPCClientProxyHandler( private fun failoverHandler(event: FailoverEventType) { when (event) { FailoverEventType.FAILURE_DETECTED -> { - lock.writeLock().withLock { - sendingEnabled = false - } + sendingEnabled.set(false) - log.warn("RPC server unavailable. RPC calls are being buffered.") log.warn("Terminating observables.") val m = observableContext.observableMap.asMap() m.keys.forEach { k -> @@ -434,9 +426,7 @@ class RPCClientProxyHandler( } FailoverEventType.FAILOVER_COMPLETED -> { - lock.writeLock().withLock { - sendingEnabled = true - } + sendingEnabled.set(true) log.info("RPC server available.") } diff --git a/node-api/build.gradle b/node-api/build.gradle index 405221b374..c99bef6f89 100644 --- a/node-api/build.gradle +++ b/node-api/build.gradle @@ -49,6 +49,19 @@ dependencies { testCompile project(':node-driver') } +configurations { + testArtifacts.extendsFrom testRuntime +} + +task testJar(type: Jar) { + classifier "tests" + from sourceSets.test.output +} + +artifacts { + testArtifacts testJar +} + jar { baseName 'corda-node-api' }