From bbd4b3b9440d19defad8e30a26e657b3483295ea Mon Sep 17 00:00:00 2001 From: Michele Sollecito Date: Thu, 28 Jun 2018 11:34:48 +0100 Subject: [PATCH] Revert "Merges: June 28th at 09:45 (#1109)" This reverts commit e5ebf04c0f113f8151dc3e5c618a07717bc8f82d. --- .../corda/client/rpc/CordaRPCClientTest.kt | 108 ++++------------- .../net/corda/client/rpc/CordaRPCClient.kt | 2 +- .../rpc/internal/RPCClientProxyHandler.kt | 2 +- .../amqp/AMQPClientSerializationScheme.kt | 20 ++- .../kotlin/rpc/StandaloneCordaRPClientTest.kt | 2 +- .../corda/core/contracts/TransactionState.kt | 5 +- docs/source/getting-set-up.rst | 28 ++++- docs/source/node-database.rst | 2 +- .../net/corda/node/internal/NodeStartup.kt | 11 +- .../statemachine/FlowStateMachineImpl.kt | 7 +- .../node/utilities/AppendOnlyPersistentMap.kt | 8 +- .../AppendOnlyPersistentMapTest.kt | 4 +- .../internal/amqp/SerializerFactory.kt | 4 +- .../testing/node/internal/ProcessUtilities.kt | 5 +- .../net/corda/smoketesting/NodeProcess.kt | 10 +- .../common/internal/TestCommonUtils.kt | 10 -- tools/demobench/build.gradle | 2 +- tools/demobench/package-demobench-exe.bat | 2 +- tools/demobench/package/bugfixes/apply.bat | 4 +- .../net/corda/demobench/model/NodeConfig.kt | 65 +++++----- .../corda/demobench/model/NodeConfigTest.kt | 114 +++++++----------- .../net/corda/tools/shell/InteractiveShell.kt | 23 +++- 22 files changed, 174 insertions(+), 264 deletions(-) delete mode 100644 testing/test-common/src/main/kotlin/net/corda/testing/common/internal/TestCommonUtils.kt diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt index 6d1d1f41a0..36926ac661 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt @@ -10,36 +10,29 @@ package net.corda.client.rpc -import net.corda.client.rpc.internal.createCordaRPCClientWithSslAndClassLoader import net.corda.core.context.* -import net.corda.core.contracts.FungibleAsset import net.corda.core.crypto.random63BitValue import net.corda.core.identity.Party import net.corda.core.internal.concurrent.flatMap -import net.corda.core.internal.location -import net.corda.core.internal.toPath +import net.corda.core.internal.packageName import net.corda.core.messaging.* -import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.finance.DOLLARS -import net.corda.finance.POUNDS import net.corda.finance.USD -import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.getCashBalance import net.corda.finance.contracts.getCashBalances import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow +import net.corda.finance.schemas.CashSchemaV1 import net.corda.node.internal.Node import net.corda.node.internal.StartedNode import net.corda.node.services.Permissions.Companion.all -import net.corda.testing.common.internal.checkNotOnClasspath import net.corda.testing.core.* import net.corda.testing.node.User import net.corda.testing.internal.IntegrationTestSchemas import net.corda.testing.internal.toDatabaseSchemaName import net.corda.testing.node.internal.NodeBasedTest -import net.corda.testing.node.internal.ProcessUtilities import org.apache.activemq.artemis.api.core.ActiveMQSecurityException import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType @@ -48,10 +41,6 @@ import org.junit.Before import org.junit.ClassRule import org.junit.Test import rx.subjects.PublishSubject -import java.io.File.pathSeparator -import java.net.URLClassLoader -import java.nio.file.Paths -import java.util.* import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import java.util.concurrent.ScheduledExecutorService @@ -60,11 +49,9 @@ import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue -class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) { - companion object { - val rpcUser = User("user1", "test", permissions = setOf(all())) - } - +class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) { + private val rpcUser = User("user1", "test", permissions = setOf(all()) + ) private lateinit var node: StartedNode private lateinit var identity: Party private lateinit var client: CordaRPCClient @@ -83,7 +70,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) { override fun setUp() { super.setUp() node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser)) - client = CordaRPCClient(node.internals.configuration.rpcOptions.address, CordaRPCClientConfiguration.DEFAULT.copy( + client = CordaRPCClient(node.internals.configuration.rpcOptions.address!!, CordaRPCClientConfiguration.DEFAULT.copy( maxReconnectAttempts = 5 )) identity = node.info.identityFromX500Name(ALICE_NAME) @@ -115,6 +102,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) { @Test fun `shutdown command stops the node`() { + val nodeIsShut: PublishSubject = PublishSubject.create() val latch = CountDownLatch(1) var successful = false @@ -161,6 +149,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) { } private class CloseableExecutor(private val delegate: ScheduledExecutorService) : AutoCloseable, ScheduledExecutorService by delegate { + override fun close() { delegate.shutdown() } @@ -239,70 +228,19 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) { ) } } - - // WireTransaction stores its components as blobs which are deserialised in its constructor. This test makes sure - // the extra class loader given to the CordaRPCClient is used in this deserialisation, as otherwise any WireTransaction - // containing Cash.State objects are not receivable by the client. - // - // We run the client in a separate process, without the finance module on its system classpath to ensure that the - // additional class loader that we give it is used. Cash.State objects are used as they can't be synthesised fully - // by the carpenter, and thus avoiding any false-positive results. - @Test - fun `additional class loader used by WireTransaction when it deserialises its components`() { - val financeLocation = Cash::class.java.location.toPath().toString() - val classpathWithoutFinance = ProcessUtilities.defaultClassPath - .split(pathSeparator) - .filter { financeLocation !in it } - .joinToString(pathSeparator) - - // Create a Cash.State object for the StandaloneCashRpcClient to get - node.services.startFlow(CashIssueFlow(100.POUNDS, OpaqueBytes.of(1), identity), InvocationContext.shell()).flatMap { it.resultFuture }.getOrThrow() - val outOfProcessRpc = ProcessUtilities.startJavaProcess( - classpath = classpathWithoutFinance, - arguments = listOf(node.internals.configuration.rpcOptions.address.toString(), financeLocation) - ) - assertThat(outOfProcessRpc.waitFor()).isZero() // i.e. no exceptions were thrown - } - - private fun checkShellNotification(info: StateMachineInfo) { - val context = info.invocationContext - assertThat(context.origin).isInstanceOf(InvocationOrigin.Shell::class.java) - } - - private fun checkRpcNotification(info: StateMachineInfo, - rpcUsername: String, - historicalIds: MutableSet, - externalTrace: Trace?, - impersonatedActor: Actor?) { - val context = info.invocationContext - assertThat(context.origin).isInstanceOf(InvocationOrigin.RPC::class.java) - assertThat(context.externalTrace).isEqualTo(externalTrace) - assertThat(context.impersonatedActor).isEqualTo(impersonatedActor) - assertThat(context.actor?.id?.value).isEqualTo(rpcUsername) - assertThat(historicalIds).doesNotContain(context.trace.invocationId) - historicalIds.add(context.trace.invocationId) - } - - private object StandaloneCashRpcClient { - @JvmStatic - fun main(args: Array) { - checkNotOnClasspath("net.corda.finance.contracts.asset.Cash") { - "The finance module cannot be on the system classpath" - } - val address = NetworkHostAndPort.parse(args[0]) - val financeClassLoader = URLClassLoader(arrayOf(Paths.get(args[1]).toUri().toURL())) - val rpcUser = CordaRPCClientTest.rpcUser - val client = createCordaRPCClientWithSslAndClassLoader(address, classLoader = financeClassLoader) - val state = client.use(rpcUser.username, rpcUser.password) { - // financeClassLoader should be allowing the Cash.State to materialise - @Suppress("DEPRECATION") - it.proxy.internalVerifiedTransactionsSnapshot()[0].tx.outputsOfType>()[0] - } - assertThat(state.javaClass.name).isEqualTo("net.corda.finance.contracts.asset.Cash${'$'}State") - assertThat(state.amount.quantity).isEqualTo(10000) - assertThat(state.amount.token.product).isEqualTo(Currency.getInstance("GBP")) - // This particular check assures us that the Cash.State we have hasn't been carpented. - assertThat(state.participants).isEqualTo(listOf(state.owner)) - } - } +} + +private fun checkShellNotification(info: StateMachineInfo) { + val context = info.invocationContext + assertThat(context.origin).isInstanceOf(InvocationOrigin.Shell::class.java) +} + +private fun checkRpcNotification(info: StateMachineInfo, rpcUsername: String, historicalIds: MutableSet, externalTrace: Trace?, impersonatedActor: Actor?) { + val context = info.invocationContext + assertThat(context.origin).isInstanceOf(InvocationOrigin.RPC::class.java) + assertThat(context.externalTrace).isEqualTo(externalTrace) + assertThat(context.impersonatedActor).isEqualTo(impersonatedActor) + assertThat(context.actor?.id?.value).isEqualTo(rpcUsername) + assertThat(historicalIds).doesNotContain(context.trace.invocationId) + historicalIds.add(context.trace.invocationId) } diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt index db41145f71..76ff61a512 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt @@ -305,7 +305,7 @@ class CordaRPCClient private constructor( effectiveSerializationEnv } catch (e: IllegalStateException) { try { - AMQPClientSerializationScheme.initialiseSerialization(classLoader) + AMQPClientSerializationScheme.initialiseSerialization() } catch (e: IllegalStateException) { // Race e.g. two of these constructed in parallel, ignore. } 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 0728820cd5..00613e9549 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 @@ -211,7 +211,7 @@ class RPCClientProxyHandler( ThreadFactoryBuilder().setNameFormat("rpc-client-reaper-%d").setDaemon(true).build() ) sendExecutor = Executors.newSingleThreadExecutor( - ThreadFactoryBuilder().setNameFormat("rpc-client-sender-%d").setDaemon(true).build() + ThreadFactoryBuilder().setNameFormat("rpc-client-sender-%d").build() ) reaperScheduledFuture = reaperExecutor!!.scheduleAtFixedRate( this::reapObservablesAndNotify, diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/serialization/amqp/AMQPClientSerializationScheme.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/serialization/amqp/AMQPClientSerializationScheme.kt index 1f82119356..389609f84c 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/serialization/amqp/AMQPClientSerializationScheme.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/serialization/amqp/AMQPClientSerializationScheme.kt @@ -3,7 +3,6 @@ package net.corda.client.rpc.internal.serialization.amqp import net.corda.core.cordapp.Cordapp import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.SerializationContext -import net.corda.core.serialization.SerializationContext.* import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.internal.SerializationEnvironment import net.corda.core.serialization.internal.SerializationEnvironmentImpl @@ -30,26 +29,25 @@ class AMQPClientSerializationScheme( companion object { /** Call from main only. */ - fun initialiseSerialization(classLoader: ClassLoader? = null) { - nodeSerializationEnv = createSerializationEnv(classLoader) + fun initialiseSerialization() { + nodeSerializationEnv = createSerializationEnv() } - fun createSerializationEnv(classLoader: ClassLoader? = null): SerializationEnvironment { + fun createSerializationEnv(): SerializationEnvironment { return SerializationEnvironmentImpl( SerializationFactoryImpl().apply { registerScheme(AMQPClientSerializationScheme(emptyList())) }, storageContext = AMQP_STORAGE_CONTEXT, - p2pContext = if (classLoader != null) AMQP_P2P_CONTEXT.withClassLoader(classLoader) else AMQP_P2P_CONTEXT, + p2pContext = AMQP_P2P_CONTEXT, rpcClientContext = AMQP_RPC_CLIENT_CONTEXT, - rpcServerContext = AMQP_RPC_SERVER_CONTEXT - ) + rpcServerContext = AMQP_RPC_SERVER_CONTEXT) } } - override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { - return magic == amqpMagic && (target == UseCase.RPCClient || target == UseCase.P2P) - } + override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase) = + magic == amqpMagic && ( + target == SerializationContext.UseCase.RPCClient || target == SerializationContext.UseCase.P2P) override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory { return SerializerFactory(context.whitelist, ClassLoader.getSystemClassLoader(), context.lenientCarpenterEnabled).apply { @@ -62,4 +60,4 @@ class AMQPClientSerializationScheme( override fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory { throw UnsupportedOperationException() } -} +} \ No newline at end of file diff --git a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt index 8f4439892d..379257b20e 100644 --- a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt +++ b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt @@ -222,7 +222,7 @@ class StandaloneCordaRPClientTest { assertEquals(1, queryResults.totalStatesAvailable) assertEquals(queryResults.states.first().state.data.amount.quantity, 629.POUNDS.quantity) - rpcProxy.startFlow(::CashPaymentFlow, 100.POUNDS, notaryNodeIdentity, true, notaryNodeIdentity).returnValue.getOrThrow() + rpcProxy.startFlow(::CashPaymentFlow, 100.POUNDS, notaryNodeIdentity).returnValue.getOrThrow() val moreResults = rpcProxy.vaultQueryBy(criteria, paging, sorting) assertEquals(3, moreResults.totalStatesAvailable) // 629 - 100 + 100 diff --git a/core/src/main/kotlin/net/corda/core/contracts/TransactionState.kt b/core/src/main/kotlin/net/corda/core/contracts/TransactionState.kt index 760e2f2ee9..0a81d244e1 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/TransactionState.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/TransactionState.kt @@ -34,8 +34,9 @@ data class TransactionState @JvmOverloads constructor( * Currently these are loaded from the classpath of the node which includes the cordapp directory - at some * point these will also be loaded and run from the attachment store directly, allowing contracts to be * sent across, and run, from the network from within a sandbox environment. - */ - // TODO: Implement the contract sandbox loading of the contract attachments + * + * TODO: Implement the contract sandbox loading of the contract attachments + * */ val contract: ContractClassName, /** Identity of the notary that ensures the state is not used as an input to a transaction more than once */ val notary: Party, diff --git a/docs/source/getting-set-up.rst b/docs/source/getting-set-up.rst index 7a681a1b40..8e0c5f09e2 100644 --- a/docs/source/getting-set-up.rst +++ b/docs/source/getting-set-up.rst @@ -79,7 +79,7 @@ IntelliJ Download a sample project ^^^^^^^^^^^^^^^^^^^^^^^^^ 1. Open a command prompt -2. Clone the ``cordapp-example`` repo by running ``git clone https://github.com/corda/cordapp-example`` +2. Clone the CorDapp example repo by running ``git clone https://github.com/corda/cordapp-example`` 3. Move into the ``cordapp-example`` folder by running ``cd cordapp-example`` 4. Checkout the branch for Corda Enterprise 3.0.0 by running ``git checkout release-enterprise-V3`` @@ -147,7 +147,7 @@ IntelliJ Download a sample project ^^^^^^^^^^^^^^^^^^^^^^^^^ 1. Open a terminal -2. Clone the ``cordapp-example`` repo by running ``git clone https://github.com/corda/cordapp-example`` +2. Clone the CorDapp example repo by running ``git clone https://github.com/corda/cordapp-example`` 3. Move into the ``cordapp-example`` folder by running ``cd cordapp-example`` 4. Checkout the branch for Corda Enterprise 3.0.0 by running ``git checkout release-enterprise-V3`` @@ -193,11 +193,31 @@ Run from IntelliJ 7. Wait until the run windows displays the message ``Webserver started up in XX.X sec`` 8. Confirm that the CorDapp is running correctly by visiting the front end at http://localhost:10009/web/example/ +Corda source code +----------------- + +The Corda platform source code is available here: + + https://github.com/corda/corda.git + +A CorDapp template that you can use as the basis for your own CorDapps is available in both Java and Kotlin versions: + + https://github.com/corda/cordapp-template-java.git + + https://github.com/corda/cordapp-template-kotlin.git + +And a list of simple sample CorDapps for you to explore basic concepts is available here: + + https://www.corda.net/samples/ + +You can clone these repos to your local machine by running the command ``git clone [repo URL]``. + Next steps ---------- -First, explore the example CorDapp you just ran :doc:`here `. +The best way to check that everything is working fine is by taking a deeper look at the +:doc:`example CorDapp `. -Next, read through :doc:`Corda Key Concepts ` to understand how Corda works. +Next, you should read through :doc:`Corda Key Concepts ` to understand how Corda works. By then, you'll be ready to start writing your own CorDapps. Learn how to do this in the :doc:`Hello, World tutorial `. You may want to refer to the API documentation, the diff --git a/docs/source/node-database.rst b/docs/source/node-database.rst index 7cbde0d287..4cd656f9ac 100644 --- a/docs/source/node-database.rst +++ b/docs/source/node-database.rst @@ -290,7 +290,7 @@ To delete existing data from the database, run the following SQL: .. _postgres_ref: PostgreSQL -`````````` +```````````````````````` Corda has been tested on PostgreSQL 9.6 database, using PostgreSQL JDBC Driver 42.1.4. To set up a database schema, use the following SQL: diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 6479f6a3cd..af281a5bd8 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -12,7 +12,6 @@ package net.corda.node.internal import com.jcabi.manifests.Manifests import com.typesafe.config.Config -import com.typesafe.config.ConfigException import com.typesafe.config.ConfigRenderOptions import io.netty.channel.unix.Errors import net.corda.core.cordapp.Cordapp @@ -120,16 +119,8 @@ open class NodeStartup(val args: Array) { } catch (e: UnknownConfigurationKeysException) { logger.error(e.message) return false - } catch (e: ConfigException.IO) { - println(""" - Unable to load the node config file from '${cmdlineOptions.configFile}'. - - Try experimenting with the --base-directory flag to change which directory the node - is looking in, or use the --config-file flag to specify it explicitly. - """.trimIndent()) - return false } catch (e: Exception) { - logger.error("Unexpected error whilst reading node configuration", e) + logger.error("Exception during node configuration", e) return false } val errors = conf.validate() diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt index 7ca967bed8..0737672e7c 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowStateMachineImpl.kt @@ -118,21 +118,19 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, if (value) field = value else throw IllegalArgumentException("Can only set to true") } - /** + /** * Processes an event by creating the associated transition and executing it using the given executor. * Try to avoid using this directly, instead use [processEventsUntilFlowIsResumed] or [processEventImmediately] * instead. */ @Suspendable private fun processEvent(transitionExecutor: TransitionExecutor, event: Event): FlowContinuation { - setLoggingContext() val stateMachine = getTransientField(TransientValues::stateMachine) val oldState = transientState!!.value val actionExecutor = getTransientField(TransientValues::actionExecutor) val transition = stateMachine.transition(event, oldState) val (continuation, newState) = transitionExecutor.executeTransition(this, oldState, event, transition, actionExecutor) transientState = TransientReference(newState) - setLoggingContext() return continuation } @@ -208,7 +206,6 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, context.pushToLoggingContext() MDC.put("flow-id", id.uuid.toString()) MDC.put("fiber-id", this.getId().toString()) - MDC.put("thread-id", Thread.currentThread().id.toString()) } @Suspendable @@ -366,7 +363,6 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, val serializationContext = TransientReference(getTransientField(TransientValues::checkpointSerializationContext)) val transaction = extractThreadLocalTransaction() parkAndSerialize { _, _ -> - setLoggingContext() logger.trace { "Suspended on $ioRequest" } // Will skip checkpoint if there are any idempotent flows in the subflow stack. @@ -393,6 +389,7 @@ class FlowStateMachineImpl(override val id: StateMachineRunId, require(continuation == FlowContinuation.ProcessEvents) unpark(SERIALIZER_BLOCKER) } + setLoggingContext() return uncheckedCast(processEventsUntilFlowIsResumed( isDbTransactionOpenOnEntry = false, isDbTransactionOpenOnExit = true diff --git a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt index 58912b3638..f262a7103b 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt @@ -133,12 +133,8 @@ abstract class AppendOnlyPersistentMapBase( } protected fun loadValue(key: K): V? { - val session = currentDBSession() - // IMPORTANT: The flush is needed because detach() makes the queue of unflushed entries invalid w.r.t. Hibernate internal state if the found entity is unflushed. - // We want the detach() so that we rely on our cache memory management and don't retain strong references in the Hibernate session. - session.flush() - val result = session.find(persistentEntityClass, toPersistentEntityKey(key)) - return result?.apply { session.detach(result) }?.let(fromPersistentEntity)?.second + val result = currentDBSession().find(persistentEntityClass, toPersistentEntityKey(key)) + return result?.apply { currentDBSession().detach(result) }?.let(fromPersistentEntity)?.second } operator fun contains(key: K) = get(key) != null diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt index 9dba0ee9a6..8d0b0800e5 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt @@ -159,9 +159,7 @@ class AppendOnlyPersistentMapTest(var scenario: Scenario) { @Test fun `test purge mid-way in a single transaction`() { // Writes intentionally do not check the database first, so purging between read and write changes behaviour - // Also, a purge after write causes the subsequent read to flush to the database, causing the read to generate a constraint violation when single threaded (in same database transaction). - val remapped = mapOf(Scenario(true, ReadOrWrite.Read, ReadOrWrite.Write, Outcome.Success, Outcome.Fail) to Scenario(true, ReadOrWrite.Read, ReadOrWrite.Write, Outcome.SuccessButErrorOnCommit, Outcome.SuccessButErrorOnCommit), - Scenario(true, ReadOrWrite.Write, ReadOrWrite.Read, Outcome.SuccessButErrorOnCommit, Outcome.Success) to Scenario(true, ReadOrWrite.Write, ReadOrWrite.Read, Outcome.SuccessButErrorOnCommit, Outcome.SuccessButErrorOnCommit)) + val remapped = mapOf(Scenario(true, ReadOrWrite.Read, ReadOrWrite.Write, Outcome.Success, Outcome.Fail) to Scenario(true, ReadOrWrite.Read, ReadOrWrite.Write, Outcome.SuccessButErrorOnCommit, Outcome.SuccessButErrorOnCommit)) scenario = remapped[scenario] ?: scenario prepopulateIfRequired() val map = createMap() diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactory.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactory.kt index 7d7198950f..f4043673c9 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactory.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactory.kt @@ -84,11 +84,11 @@ open class SerializerFactory( @DeleteForDJVM constructor(whitelist: ClassWhitelist, - carpenterClassLoader: ClassLoader, + classLoader: ClassLoader, lenientCarpenter: Boolean = false, evolutionSerializerGetter: EvolutionSerializerGetterBase = EvolutionSerializerGetter(), fingerPrinter: FingerPrinter = SerializerFingerPrinter() - ) : this(whitelist, ClassCarpenterImpl(whitelist, carpenterClassLoader, lenientCarpenter), evolutionSerializerGetter, fingerPrinter) + ) : this(whitelist, ClassCarpenterImpl(whitelist, classLoader, lenientCarpenter), evolutionSerializerGetter, fingerPrinter) init { fingerPrinter.setOwner(this) diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt index ae2c0502ca..fa97cd88cc 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/ProcessUtilities.kt @@ -11,16 +11,17 @@ package net.corda.testing.node.internal import net.corda.core.internal.div +import net.corda.core.internal.exists +import java.io.File.pathSeparator import java.nio.file.Path object ProcessUtilities { inline fun startJavaProcess( arguments: List, - classpath: String = defaultClassPath, jdwpPort: Int? = null, extraJvmArguments: List = emptyList() ): Process { - return startJavaProcessImpl(C::class.java.name, arguments, classpath, jdwpPort, extraJvmArguments, null, null) + return startJavaProcessImpl(C::class.java.name, arguments, defaultClassPath, jdwpPort, extraJvmArguments, null, null) } fun startCordaProcess( diff --git a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt index dd16e9db7f..6d92fe9bfd 100644 --- a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt +++ b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeProcess.kt @@ -18,7 +18,6 @@ import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.contextLogger import net.corda.nodeapi.internal.network.NetworkParametersCopier import net.corda.testing.common.internal.asContextEnv -import net.corda.testing.common.internal.checkNotOnClasspath import net.corda.testing.common.internal.testNetworkParameters import java.io.File import java.nio.file.Path @@ -76,15 +75,18 @@ class NodeProcess( val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(systemDefault()) val defaultNetworkParameters = run { AMQPClientSerializationScheme.createSerializationEnv().asContextEnv { - // TODO There are no notaries in the network parameters for smoke test nodes. If this is required then we would + // There are no notaries in the network parameters for smoke test nodes. If this is required then we would // need to introduce the concept of a "network" which predefines the notaries, like the driver and MockNetwork NetworkParametersCopier(testNetworkParameters()) } } init { - checkNotOnClasspath("net.corda.node.Corda") { - "Smoke test has the node in its classpath. Please remove the offending dependency." + try { + Class.forName("net.corda.node.Corda") + throw Error("Smoke test has the node in its classpath. Please remove the offending dependency.") + } catch (e: ClassNotFoundException) { + // If the class can't be found then we're good! } } } diff --git a/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/TestCommonUtils.kt b/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/TestCommonUtils.kt deleted file mode 100644 index 5ae693498e..0000000000 --- a/testing/test-common/src/main/kotlin/net/corda/testing/common/internal/TestCommonUtils.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.corda.testing.common.internal - -inline fun checkNotOnClasspath(className: String, errorMessage: () -> Any) { - try { - Class.forName(className) - throw IllegalStateException(errorMessage().toString()) - } catch (e: ClassNotFoundException) { - // If the class can't be found then we're good! - } -} diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index aa0920d2ce..0500652ea4 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -46,8 +46,8 @@ repositories { flatDir { dirs 'libs' } - jcenter() maven { + jcenter() url 'http://www.sparetimelabs.com/maven2' } } diff --git a/tools/demobench/package-demobench-exe.bat b/tools/demobench/package-demobench-exe.bat index 5cbfd851a6..c2f0b41e80 100644 --- a/tools/demobench/package-demobench-exe.bat +++ b/tools/demobench/package-demobench-exe.bat @@ -11,7 +11,7 @@ if "%DIRNAME%" == "" set DIRNAME=. call %DIRNAME%\..\..\gradlew -PpackageType=exe javapackage %* if ERRORLEVEL 1 goto Fail @echo -@echo Wrote installer to %DIRNAME%build\javapackage\bundles\ +@echo Wrote installer to %DIRNAME%\build\javapackage\bundles\ @echo goto end diff --git a/tools/demobench/package/bugfixes/apply.bat b/tools/demobench/package/bugfixes/apply.bat index ba500032c1..747dc67852 100644 --- a/tools/demobench/package/bugfixes/apply.bat +++ b/tools/demobench/package/bugfixes/apply.bat @@ -29,14 +29,14 @@ if exist "%BUILDDIR%" rmdir /s /q "%BUILDDIR%" mkdir "%BUILDDIR%" for /r "%SOURCEDIR%" %%j in (*.java) do ( - "%JAVA_HOME%\bin\javac" -O -d "%BUILDDIR%" "%%j" + javac -O -d "%BUILDDIR%" "%%j" if ERRORLEVEL 1 ( @echo "Failed to compile %%j" exit /b 1 ) ) -"%JAVA_HOME%\bin\jar" uvf %1 -C "%BUILDDIR%" . +jar uvf %1 -C "%BUILDDIR%" . if ERRORLEVEL 1 ( @echo "Failed to update %1" exit /b 1 diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index 0513b3a071..f66fbde2a4 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -10,8 +10,10 @@ package net.corda.demobench.model -import com.typesafe.config.* +import com.typesafe.config.Config import com.typesafe.config.ConfigFactory.empty +import com.typesafe.config.ConfigRenderOptions +import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name import net.corda.core.internal.copyToDirectory import net.corda.core.internal.createDirectories @@ -53,22 +55,13 @@ data class NodeConfig( } fun nodeConf(): Config { - val rpcSettings: ConfigObject = empty() - .withValue("address", valueFor(rpcAddress.toString())) - .withValue("adminAddress", valueFor(rpcAdminAddress.toString())) - .root() - val customMap: Map = HashMap().also { - if (issuableCurrencies.isNotEmpty()) { - it["issuableCurrencies"] = issuableCurrencies - } - } - val custom: ConfigObject = ConfigFactory.parseMap(customMap).root() - return NodeConfigurationData(myLegalName, p2pAddress, rpcAddress, notary, h2port, rpcUsers, useTestClock, detectPublicIp, devMode) - .toConfig() - .withoutPath("rpcAddress") - .withoutPath("rpcAdminAddress") - .withValue("rpcSettings", rpcSettings) - .withOptionalValue("custom", custom) + + val basic = NodeConfigurationData(myLegalName, p2pAddress, rpcAddress, notary, h2port, rpcUsers, useTestClock, detectPublicIp, devMode).toConfig() + val rpcSettings = empty() + .withValue("address", ConfigValueFactory.fromAnyRef(rpcAddress.toString())) + .withValue("adminAddress", ConfigValueFactory.fromAnyRef(rpcAdminAddress.toString())) + .root() + return basic.withoutPath("rpcAddress").withoutPath("rpcAdminAddress").withValue("rpcSettings", rpcSettings) } fun webServerConf() = WebServerConfigurationData(myLegalName, rpcAddress, webAddress, rpcUsers).asConfig() @@ -77,29 +70,33 @@ data class NodeConfig( fun toWebServerConfText() = webServerConf().render() - fun serialiseAsString(): String = toConfig().render() + fun serialiseAsString(): String { + + return toConfig().render() + } private fun Config.render(): String = root().render(renderOptions) } private data class NodeConfigurationData( - val myLegalName: CordaX500Name, - val p2pAddress: NetworkHostAndPort, - val rpcAddress: NetworkHostAndPort, - val notary: NotaryService?, - val h2port: Int, - val rpcUsers: List = listOf(NodeConfig.defaultUser), - val useTestClock: Boolean, - val detectPublicIp: Boolean, - val devMode: Boolean + val myLegalName: CordaX500Name, + val p2pAddress: NetworkHostAndPort, + val rpcAddress: NetworkHostAndPort, + val notary: NotaryService?, + val h2port: Int, + val rpcUsers: List = listOf(NodeConfig.defaultUser), + val useTestClock: Boolean, + val detectPublicIp: Boolean, + val devMode: Boolean ) private data class WebServerConfigurationData( - val myLegalName: CordaX500Name, - val rpcAddress: NetworkHostAndPort, - val webAddress: NetworkHostAndPort, - val rpcUsers: List + val myLegalName: CordaX500Name, + val rpcAddress: NetworkHostAndPort, + val webAddress: NetworkHostAndPort, + val rpcUsers: List ) { + fun asConfig() = toConfig() } @@ -130,9 +127,3 @@ data class NodeConfigWrapper(val baseDir: Path, val nodeConfig: NodeConfig) : Ha fun user(name: String) = User(name, "letmein", setOf("ALL")) fun String.toKey() = filter { !it.isWhitespace() }.toLowerCase() - -fun valueFor(any: T): ConfigValue = ConfigValueFactory.fromAnyRef(any) - -private fun Config.withOptionalValue(path: String, obj: ConfigObject): Config { - return if (obj.isEmpty()) this else this.withValue(path, obj) -} diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt index ee066821cc..75d5a37fa1 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt @@ -10,18 +10,21 @@ package net.corda.demobench.model -import com.typesafe.config.ConfigException import com.typesafe.config.ConfigFactory +import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.services.config.parseAsNodeConfiguration import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.persistence.CordaPersistence.DataSourceConfigTag import net.corda.webserver.WebServerConfig +import org.assertj.core.api.Assertions.assertThat import org.junit.Test import java.nio.file.Path import java.nio.file.Paths -import kotlin.test.* +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue class NodeConfigTest { companion object { @@ -32,26 +35,23 @@ class NodeConfigTest { @Test fun `reading node configuration`() { val config = createConfig( - legalName = myLegalName, - p2pPort = 10001, - rpcPort = 40002, - rpcAdminPort = 40005, - webPort = 20001, - h2port = 30001, - notary = NotaryService(validating = false), - users = listOf(user("jenny")) + legalName = myLegalName, + p2pPort = 10001, + rpcPort = 40002, + rpcAdminPort = 40005, + webPort = 20001, + h2port = 30001, + notary = NotaryService(validating = false), + users = listOf(user("jenny")) ) val nodeConfig = config.nodeConf() - .withValue("baseDirectory", valueFor(baseDir.toString())) - .withFallback(ConfigFactory.parseResources("reference.conf")) - .withFallback(ConfigFactory.parseMap(mapOf("devMode" to true))) - .resolve() + .withValue("baseDirectory", ConfigValueFactory.fromAnyRef(baseDir.toString())) + .withFallback(ConfigFactory.parseResources("reference.conf")) + .withFallback(ConfigFactory.parseMap(mapOf("devMode" to true))) + .resolve() val fullConfig = nodeConfig.parseAsNodeConfiguration() - // No custom configuration is created by default. - assertFailsWith { nodeConfig.getConfig("custom") } - assertEquals(myLegalName, fullConfig.myLegalName) assertEquals(localPort(40002), fullConfig.rpcOptions.address) assertEquals(localPort(10001), fullConfig.p2pAddress) @@ -60,49 +60,25 @@ class NodeConfigTest { assertFalse(fullConfig.detectPublicIp) } - @Test - fun `reading node configuration with currencies`() { - val config = createConfig( - legalName = myLegalName, - p2pPort = 10001, - rpcPort = 10002, - rpcAdminPort = 10003, - webPort = 10004, - h2port = 10005, - notary = NotaryService(validating = false), - issuableCurrencies = listOf("GBP") - ) - - val nodeConfig = config.nodeConf() - .withValue("baseDirectory", valueFor(baseDir.toString())) - .withFallback(ConfigFactory.parseResources("reference.conf")) - .resolve() - val custom = nodeConfig.getConfig("custom") - assertEquals(listOf("GBP"), custom.getAnyRefList("issuableCurrencies")) - } - @Test fun `reading webserver configuration`() { val config = createConfig( - legalName = myLegalName, - p2pPort = 10001, - rpcPort = 40002, - rpcAdminPort = 40003, - webPort = 20001, - h2port = 30001, - notary = NotaryService(validating = false), - users = listOf(user("jenny")) + legalName = myLegalName, + p2pPort = 10001, + rpcPort = 40002, + rpcAdminPort = 40003, + webPort = 20001, + h2port = 30001, + notary = NotaryService(validating = false), + users = listOf(user("jenny")) ) val nodeConfig = config.webServerConf() - .withValue("baseDirectory", valueFor(baseDir.toString())) - .withFallback(ConfigFactory.parseResources("web-reference.conf")) - .resolve() + .withValue("baseDirectory", ConfigValueFactory.fromAnyRef(baseDir.toString())) + .withFallback(ConfigFactory.parseResources("web-reference.conf")) + .resolve() val webConfig = WebServerConfig(baseDir, nodeConfig) - // No custom configuration is created by default. - assertFailsWith { nodeConfig.getConfig("custom") } - assertEquals(localPort(20001), webConfig.webAddress) assertEquals(localPort(40002), webConfig.rpcAddress) assertEquals("trustpass", webConfig.trustStorePassword) @@ -110,26 +86,24 @@ class NodeConfigTest { } private fun createConfig( - legalName: CordaX500Name = CordaX500Name(organisation = "Unknown", locality = "Nowhere", country = "GB"), - p2pPort: Int = -1, - rpcPort: Int = -1, - rpcAdminPort: Int = -1, - webPort: Int = -1, - h2port: Int = -1, - notary: NotaryService?, - users: List = listOf(user("guest")), - issuableCurrencies: List = emptyList() + legalName: CordaX500Name = CordaX500Name(organisation = "Unknown", locality = "Nowhere", country = "GB"), + p2pPort: Int = -1, + rpcPort: Int = -1, + rpcAdminPort: Int = -1, + webPort: Int = -1, + h2port: Int = -1, + notary: NotaryService?, + users: List = listOf(user("guest")) ): NodeConfig { return NodeConfig( - myLegalName = legalName, - p2pAddress = localPort(p2pPort), - rpcAddress = localPort(rpcPort), - rpcAdminAddress = localPort(rpcAdminPort), - webAddress = localPort(webPort), - h2port = h2port, - notary = notary, - rpcUsers = users, - issuableCurrencies = issuableCurrencies + myLegalName = legalName, + p2pAddress = localPort(p2pPort), + rpcAddress = localPort(rpcPort), + rpcAdminAddress = localPort(rpcAdminPort), + webAddress = localPort(webPort), + h2port = h2port, + notary = notary, + rpcUsers = users ) } diff --git a/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt b/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt index 5d26cd4b1e..09916ed81e 100644 --- a/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt +++ b/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt @@ -25,10 +25,18 @@ import net.corda.core.CordaException import net.corda.core.concurrent.CordaFuture import net.corda.core.contracts.UniqueIdentifier import net.corda.core.flows.FlowLogic -import net.corda.core.internal.* +import net.corda.core.internal.Emoji import net.corda.core.internal.concurrent.doneFuture import net.corda.core.internal.concurrent.openFuture -import net.corda.core.messaging.* +import net.corda.core.internal.createDirectories +import net.corda.core.internal.div +import net.corda.core.internal.rootCause +import net.corda.core.internal.uncheckedCast +import net.corda.core.messaging.CordaRPCOps +import net.corda.core.messaging.DataFeed +import net.corda.core.messaging.FlowProgressHandle +import net.corda.core.messaging.StateMachineUpdate +import net.corda.core.messaging.pendingFlowsCount import net.corda.tools.shell.utlities.ANSIProgressRenderer import net.corda.tools.shell.utlities.StdoutANSIProgressRenderer import org.crsh.command.InvocationContext @@ -133,7 +141,8 @@ object InteractiveShell { config["crash.ssh.port"] = configuration.sshdPort?.toString() config["crash.auth"] = "corda" configuration.sshHostKeyDirectory?.apply { - val sshKeysDir = configuration.sshHostKeyDirectory.createDirectories() + val sshKeysDir = configuration.sshHostKeyDirectory + sshKeysDir.createDirectories() config["crash.ssh.keypath"] = (sshKeysDir / "hostkey.pem").toString() config["crash.ssh.keygen"] = "true" } @@ -276,7 +285,7 @@ object InteractiveShell { val stateObservable = runFlowFromString({ clazz, args -> rpcOps.startTrackedFlowDynamic(clazz, *args) }, inputData, flowClazz, om) val latch = CountDownLatch(1) - ansiProgressRenderer.render(stateObservable, latch::countDown) + ansiProgressRenderer.render(stateObservable, { latch.countDown() }) // Wait for the flow to end and the progress tracker to notice. By the time the latch is released // the tracker is done with the screen. while (!Thread.currentThread().isInterrupted) { @@ -292,7 +301,11 @@ object InteractiveShell { } } } - output.println("Flow completed with result: ${stateObservable.returnValue.get()}") + stateObservable.returnValue.get()?.apply { + if (this !is Throwable) { + output.println("Flow completed with result: $this") + } + } } catch (e: NoApplicableConstructor) { output.println("No matching constructor found:", Color.red) e.errors.forEach { output.println("- $it", Color.red) }