Merge pull request #1302 from corda/df-merge-2018-07-25

Df merge 2018 07 25
This commit is contained in:
Eric McEvoy 2018-07-26 09:47:15 +01:00 committed by GitHub
commit aec217a065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 499 additions and 267 deletions

View File

@ -18,8 +18,8 @@ import net.corda.finance.flows.AbstractCashFlow;
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.internal.StartedNodeWithInternals;
import net.corda.testing.internal.InternalTestUtilsKt;
import net.corda.testing.node.User;
import net.corda.testing.internal.IntegrationTestKt;
@ -60,7 +60,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
private Set<String> permSet = new HashSet<>(perms);
private User rpcUser = new User("user1", "test", permSet);
private StartedNode<Node> node;
private StartedNodeWithInternals node;
private CordaRPCClient client;
private RPCConnection<CordaRPCOps> connection = null;
private CordaRPCOps rpcProxy;

View File

@ -30,8 +30,7 @@ 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.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions.Companion.all
import net.corda.testing.common.internal.checkNotOnClasspath
import net.corda.testing.core.*
@ -68,7 +67,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName())
}
private lateinit var node: StartedNode<Node>
private lateinit var node: StartedNodeWithInternals
private lateinit var identity: Party
private lateinit var client: CordaRPCClient
private var connection: CordaRPCConnection? = null

View File

@ -16,8 +16,7 @@ import net.corda.core.internal.packageName
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.getOrThrow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions
import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.testing.core.ALICE_NAME
@ -79,7 +78,7 @@ class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contract
}
private val rpcUser = User("user1", "test", permissions = setOf(Permissions.all()))
private lateinit var node: StartedNode<Node>
private lateinit var node: StartedNodeWithInternals
private lateinit var client: CordaRPCClient
@Before

View File

@ -11,8 +11,9 @@
package net.corda.core.crypto;
import net.corda.core.KeepForDJVM;
import java.math.*;
import java.util.*;
import java.math.BigInteger;
import java.util.Arrays;
/**
* Base58 is a way to encode Bitcoin addresses (or arbitrary data) as alphanumeric strings.

View File

@ -10,7 +10,7 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
/**

View File

@ -1,9 +1,7 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
import kotlin.annotation.Retention
import kotlin.annotation.Target
/**
* Declare the annotated element to unsuitable for the deterministic version of Corda.

View File

@ -1,9 +1,8 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationTarget.*
import kotlin.annotation.Retention
import kotlin.annotation.Target
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FILE
/**
* This annotates a class or file that we want to include into the deterministic version of Corda Core.

View File

@ -1,9 +1,7 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
import kotlin.annotation.Retention
import kotlin.annotation.Target
/**
* We expect that almost every non-deterministic element can have its bytecode

View File

@ -11,9 +11,9 @@
@file:JvmName("ConcurrencyUtils")
package net.corda.core.concurrent
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.concurrent.openFuture
import net.corda.core.utilities.getOrThrow
import net.corda.core.internal.VisibleForTesting
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.concurrent.Future

View File

@ -13,8 +13,8 @@ package net.corda.core.identity
import net.corda.core.KeepForDJVM
import net.corda.core.internal.LegalNameValidator
import net.corda.core.internal.toAttributesMap
import net.corda.core.internal.unspecifiedCountry
import net.corda.core.internal.toX500Name
import net.corda.core.internal.unspecifiedCountry
import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.x500.style.BCStyle
import java.util.*

View File

@ -10,9 +10,9 @@
package net.corda.core.internal.concurrent
import net.corda.core.internal.VisibleForTesting
import net.corda.core.concurrent.CordaFuture
import net.corda.core.concurrent.match
import net.corda.core.internal.VisibleForTesting
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow
import org.slf4j.Logger

View File

@ -14,18 +14,12 @@ import net.corda.core.internal.concurrent.OpenFuture;
import org.junit.Test;
import java.io.EOFException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.*;
import static net.corda.core.internal.concurrent.CordaFutureImplKt.doneFuture;
import static net.corda.core.internal.concurrent.CordaFutureImplKt.openFuture;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
public class CordaFutureInJavaTest {
@Test

View File

@ -158,18 +158,18 @@ class AttachmentTests : WithMockNet {
//endregion
//region Operations
private fun StartedNode<*>.importAttachment(attachment: ByteArray) =
private fun StartedNode.importAttachment(attachment: ByteArray) =
attachments.importAttachment(attachment.inputStream(), "test", null)
.andRunNetwork()
private fun StartedNode<*>.updateAttachment(attachment: NodeAttachmentService.DBAttachment) = database.transaction {
private fun StartedNode.updateAttachment(attachment: NodeAttachmentService.DBAttachment) = database.transaction {
session.update(attachment)
}.andRunNetwork()
private fun StartedNode<*>.startAttachmentFlow(hash: SecureHash, otherSide: Party) = startFlowAndRunNetwork(
private fun StartedNode.startAttachmentFlow(hash: SecureHash, otherSide: Party) = startFlowAndRunNetwork(
InitiatingFetchAttachmentsFlow(otherSide, setOf(hash)))
private fun StartedNode<*>.getAttachmentWithId(id: SecureHash) =
private fun StartedNode.getAttachmentWithId(id: SecureHash) =
attachments.openAttachment(id)!!
//endregion

View File

@ -103,7 +103,7 @@ class CollectSignaturesFlowTests : WithContracts {
}
//region Operators
private fun StartedNode<*>.startTestFlow(vararg party: Party) =
private fun StartedNode.startTestFlow(vararg party: Party) =
startFlowAndRunNetwork(
TestFlow.Initiator(DummyContract.MultiOwnerState(
MAGIC_NUMBER,

View File

@ -24,7 +24,6 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.User
import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import org.junit.AfterClass
import org.junit.Test
@ -85,7 +84,7 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
}
//region RPC DSL
private fun RPCDriverDSL.startProxy(node: StartedNode<MockNode>, user: User): CordaRPCOps {
private fun RPCDriverDSL.startProxy(node: StartedNode, user: User): CordaRPCOps {
return startRpcClient<CordaRPCOps>(
rpcAddress = startRpcServer(
rpcUser = user,
@ -113,16 +112,16 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
//endregion
//region Matchers
private fun StartedNode<*>.hasDummyContractUpgradeTransaction() =
private fun StartedNode.hasDummyContractUpgradeTransaction() =
hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>()
private inline fun <reified FROM : Any, reified TO: Any> StartedNode<*>.hasContractUpgradeTransaction() =
private inline fun <reified FROM : Any, reified TO: Any> StartedNode.hasContractUpgradeTransaction() =
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
"a contract upgrade transaction",
{ getContractUpgradeTransaction(it) },
isUpgrade<FROM, TO>())
private fun StartedNode<*>.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
private fun StartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
services.validatedTransactions.getTransaction(state.ref.txhash)!!
.resolveContractUpgradeTransaction(services)

View File

@ -95,14 +95,14 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
and bobNode.hasDummyContractUpgradeTransaction()))
}
private fun StartedNode<*>.issueCash(amount: Amount<Currency> = Amount(1000, USD)) =
private fun StartedNode.issueCash(amount: Amount<Currency> = Amount(1000, USD)) =
services.startFlow(CashIssueFlow(amount, OpaqueBytes.of(1), notary))
.andRunNetwork()
.resultFuture.getOrThrow()
private fun StartedNode<*>.getBaseStateFromVault() = getStateFromVault(ContractState::class)
private fun StartedNode.getBaseStateFromVault() = getStateFromVault(ContractState::class)
private fun StartedNode<*>.getCashStateFromVault() = getStateFromVault(CashV2.State::class)
private fun StartedNode.getCashStateFromVault() = getStateFromVault(CashV2.State::class)
private fun hasIssuedAmount(expected: Amount<Issued<Currency>>) =
hasContractState(has(CashV2.State::amount, equalTo(expected)))
@ -172,24 +172,24 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
}
//region Operations
private fun StartedNode<*>.initiateDummyContractUpgrade(tx: SignedTransaction) =
private fun StartedNode.initiateDummyContractUpgrade(tx: SignedTransaction) =
initiateContractUpgrade(tx, DummyContractV2::class)
private fun StartedNode<*>.authoriseDummyContractUpgrade(tx: SignedTransaction) =
private fun StartedNode.authoriseDummyContractUpgrade(tx: SignedTransaction) =
authoriseContractUpgrade(tx, DummyContractV2::class)
//endregion
//region Matchers
private fun StartedNode<*>.hasDummyContractUpgradeTransaction() =
private fun StartedNode.hasDummyContractUpgradeTransaction() =
hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>()
private inline fun <reified FROM : Any, reified TO: Any> StartedNode<*>.hasContractUpgradeTransaction() =
private inline fun <reified FROM : Any, reified TO: Any> StartedNode.hasContractUpgradeTransaction() =
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
"a contract upgrade transaction",
{ getContractUpgradeTransaction(it) },
isUpgrade<FROM, TO>())
private fun StartedNode<*>.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
private fun StartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
services.validatedTransactions.getTransaction(state.ref.txhash)!!
.resolveContractUpgradeTransaction(services)

View File

@ -68,7 +68,7 @@ class FinalityFlowTests : WithFinality {
willThrow<IllegalArgumentException>())
}
private fun StartedNode<*>.signCashTransactionWith(other: Party): SignedTransaction {
private fun StartedNode.signCashTransactionWith(other: Party): SignedTransaction {
val amount = 1000.POUNDS.issuedBy(alice.ref(0))
val builder = TransactionBuilder(notary)
Cash().generateIssue(builder, amount, other, notary)

View File

@ -14,8 +14,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.utilities.UntrustworthyData
import net.corda.core.utilities.unwrap
import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import kotlin.reflect.KClass
/**
@ -48,14 +47,14 @@ class NoAnswer(private val closure: () -> Unit = {}) : FlowLogic<Unit>() {
/**
* Allows to register a flow of type [R] against an initiating flow of type [I].
*/
inline fun <I : FlowLogic<*>, reified R : FlowLogic<*>> StartedNode<*>.registerInitiatedFlow(initiatingFlowType: KClass<I>, crossinline construct: (session: FlowSession) -> R) {
inline fun <I : FlowLogic<*>, reified R : FlowLogic<*>> TestStartedNode.registerInitiatedFlow(initiatingFlowType: KClass<I>, crossinline construct: (session: FlowSession) -> R) {
internalRegisterFlowFactory(initiatingFlowType.java, InitiatedFlowFactory.Core { session -> construct(session) }, R::class.javaObjectType, true)
}
/**
* Allows to register a flow of type [Answer] against an initiating flow of type [I], returning a valure of type [R].
*/
inline fun <I : FlowLogic<*>, reified R : Any> StartedNode<InternalMockNetwork.MockNode>.registerAnswer(initiatingFlowType: KClass<I>, value: R) {
inline fun <I : FlowLogic<*>, reified R : Any> TestStartedNode.registerAnswer(initiatingFlowType: KClass<I>, value: R) {
internalRegisterFlowFactory(initiatingFlowType.java, InitiatedFlowFactory.Core { session -> Answer(session, value) }, Answer::class.javaObjectType, true)
}

View File

@ -12,8 +12,6 @@ package net.corda.core.flows
import co.paralleluniverse.fibers.Suspendable
import com.natpryce.hamkrest.assertion.assert
import com.natpryce.hamkrest.equalTo
import com.natpryce.hamkrest.isA
import net.corda.core.flows.matchers.flow.willReturn
import net.corda.core.flows.mixins.WithMockNet
import net.corda.core.identity.Party

View File

@ -3,8 +3,8 @@ package net.corda.core.flows.matchers.flow
import com.natpryce.hamkrest.Matcher
import com.natpryce.hamkrest.equalTo
import com.natpryce.hamkrest.has
import net.corda.core.flows.matchers.willThrow
import net.corda.core.flows.matchers.willReturn
import net.corda.core.flows.matchers.willThrow
import net.corda.core.internal.FlowStateMachine
/**

View File

@ -2,8 +2,8 @@ package net.corda.core.flows.matchers.rpc
import com.natpryce.hamkrest.Matcher
import com.natpryce.hamkrest.has
import net.corda.core.flows.matchers.willThrow
import net.corda.core.flows.matchers.willReturn
import net.corda.core.flows.matchers.willThrow
import net.corda.core.messaging.FlowHandle
/**

View File

@ -29,33 +29,33 @@ interface WithContracts : WithMockNet {
//region
//region Operations
fun StartedNode<*>.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
fun StartedNode.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
services.signDummyContract(owner, magicNumber, *others).andRunNetwork()
fun ServiceHub.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
signInitialTransaction(createDummyContract(owner, magicNumber, *others))
fun StartedNode<*>.collectSignatures(ptx: SignedTransaction) =
fun StartedNode.collectSignatures(ptx: SignedTransaction) =
startFlowAndRunNetwork(CollectSignaturesFlow(ptx, emptySet()))
fun StartedNode<*>.addSignatureTo(ptx: SignedTransaction) =
fun StartedNode.addSignatureTo(ptx: SignedTransaction) =
services.addSignature(ptx).andRunNetwork()
fun <T : UpgradedContract<*, *>>
StartedNode<*>.initiateContractUpgrade(tx: SignedTransaction, toClass: KClass<T>) =
StartedNode.initiateContractUpgrade(tx: SignedTransaction, toClass: KClass<T>) =
initiateContractUpgrade(tx.tx.outRef(0), toClass)
fun <S : ContractState, T : UpgradedContract<S, *>>
StartedNode<*>.initiateContractUpgrade(stateAndRef: StateAndRef<S>, toClass: KClass<T>) =
StartedNode.initiateContractUpgrade(stateAndRef: StateAndRef<S>, toClass: KClass<T>) =
startFlowAndRunNetwork(ContractUpgradeFlow.Initiate(stateAndRef, toClass.java))
fun <T : UpgradedContract<*, *>> StartedNode<*>.authoriseContractUpgrade(
fun <T : UpgradedContract<*, *>> StartedNode.authoriseContractUpgrade(
tx: SignedTransaction, toClass: KClass<T>) =
startFlow(
ContractUpgradeFlow.Authorise(tx.tx.outRef<ContractState>(0), toClass.java)
)
fun StartedNode<*>.deauthoriseContractUpgrade(tx: SignedTransaction) = startFlow(
fun StartedNode.deauthoriseContractUpgrade(tx: SignedTransaction) = startFlow(
ContractUpgradeFlow.Deauthorise(tx.tx.outRef<ContractState>(0).ref)
)

View File

@ -16,10 +16,10 @@ import net.corda.testing.core.singleIdentity
interface WithFinality : WithMockNet {
//region Operations
fun StartedNode<*>.finalise(stx: SignedTransaction, vararg additionalParties: Party) =
fun StartedNode.finalise(stx: SignedTransaction, vararg additionalParties: Party) =
startFlowAndRunNetwork(FinalityFlow(stx, additionalParties.toSet()))
fun StartedNode<*>.getValidatedTransaction(stx: SignedTransaction) =
fun StartedNode.getValidatedTransaction(stx: SignedTransaction) =
services.validatedTransactions.getTransaction(stx.id)!!
fun CordaRPCOps.finalise(stx: SignedTransaction, vararg parties: Party) =
@ -28,7 +28,7 @@ interface WithFinality : WithMockNet {
//endregion
//region Matchers
fun visibleTo(other: StartedNode<*>) = object : Matcher<SignedTransaction> {
fun visibleTo(other: StartedNode) = object : Matcher<SignedTransaction> {
override val description = "has a transaction visible to ${other.info.singleIdentity()}"
override fun invoke(actual: SignedTransaction) =
equalTo(actual)(other.getValidatedTransaction(actual))

View File

@ -41,32 +41,32 @@ interface WithMockNet {
/**
* Sign an initial transaction
*/
fun StartedNode<*>.signInitialTransaction(build: TransactionBuilder.() -> TransactionBuilder) =
fun StartedNode.signInitialTransaction(build: TransactionBuilder.() -> TransactionBuilder) =
services.signInitialTransaction(TransactionBuilder(mockNet.defaultNotaryIdentity).build())
/**
* Retrieve the sole instance of a state of a particular class from the node's vault
*/
fun <S: ContractState> StartedNode<*>.getStateFromVault(stateClass: KClass<S>) =
fun <S: ContractState> StartedNode.getStateFromVault(stateClass: KClass<S>) =
services.vaultService.queryBy(stateClass.java).states.single()
/**
* Start a flow
*/
fun <T> StartedNode<*>.startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = services.startFlow(logic)
fun <T> StartedNode.startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = services.startFlow(logic)
/**
* Start a flow and run the network immediately afterwards
*/
fun <T> StartedNode<*>.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> =
fun <T> StartedNode.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> =
startFlow(logic).andRunNetwork()
fun StartedNode<*>.createConfidentialIdentity(party: Party) =
fun StartedNode.createConfidentialIdentity(party: Party) =
services.keyManagementService.freshKeyAndCert(
services.myInfo.legalIdentitiesAndCerts.single { it.name == party.name },
false)
fun StartedNode<*>.verifyAndRegister(identity: PartyAndCertificate) =
fun StartedNode.verifyAndRegister(identity: PartyAndCertificate) =
services.identityService.verifyAndRegisterIdentity(identity)
//endregion

View File

@ -31,6 +31,7 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow
import org.junit.After
import org.junit.Before
@ -54,11 +55,11 @@ private fun
Attachment.extractContent() = ByteArrayOutputStream().apply { extractFile("content", this) }.toString(UTF_8.name())
@Suppress("deprecation")
private fun StartedNode<*>.saveAttachment(content: String) = database.transaction {
private fun StartedNode.saveAttachment(content: String) = database.transaction {
attachments.importAttachment(createAttachmentData(content).inputStream())
}
private fun StartedNode<*>.hackAttachment(attachmentId: SecureHash, content: String) = database.transaction {
private fun StartedNode.hackAttachment(attachmentId: SecureHash, content: String) = database.transaction {
updateAttachment(attachmentId, createAttachmentData(content))
}
@ -76,8 +77,8 @@ private fun updateAttachment(attachmentId: SecureHash, data: ByteArray) {
class AttachmentSerializationTest {
private lateinit var mockNet: InternalMockNetwork
private lateinit var server: StartedNode<InternalMockNetwork.MockNode>
private lateinit var client: StartedNode<InternalMockNetwork.MockNode>
private lateinit var server: TestStartedNode
private lateinit var client: TestStartedNode
private lateinit var serverIdentity: Party
@Before

View File

@ -10,6 +10,8 @@ Unreleased
* Change type of the `checkpoint_value` column. Please check the upgrade-notes on how to update your database.
* Removed buggy :serverNameTablePrefix: configuration.
* ``freeLocalHostAndPort``, ``freePort``, and ``getFreeLocalPorts`` from ``TestUtils`` have been deprecated as they
don't provide any guarantee the returned port will be available which can result in flaky tests. Use ``PortAllocation.Incremental``
instead.

View File

@ -44,8 +44,8 @@ Let's open the example CorDapp in IntelliJ IDEA:
* A splash screen will appear. Click ``open``, select the cloned ``cordapp-example`` folder, and click ``OK``
* Once the project is open, click ``File``, then ``Project Structure``. Under ``Project SDK:``, set the project SDK by
clicking ``New...``, clicking ``JDK``, and navigating to ``C:\Program Files\Java\jdk1.8.0_XXX`` (where ``XXX`` is the
latest minor version number). Click ``OK``
clicking ``New...``, clicking ``JDK``, and navigating to ``C:\Program Files\Java\jdk1.8.0_XXX`` on Windows or ``Library/Java/JavaVirtualMachines/jdk1.8.XXX`` on MacOSX (where ``XXX`` is the
latest minor version number). Click ``Apply`` followed by ``OK``
* Again under ``File`` then ``Project Structure``, select ``Modules``. Click ``+``, then ``Import Module``, then select
the ``cordapp-example`` folder and click ``Open``. Choose to ``Import module from external model``, select

View File

@ -22,10 +22,64 @@ Upgrading to |release| from Open Source 3.x requires updating build file propert
.. sourcecode:: shell
<<<<<<< HEAD
ext.corda_release_distribution = 'com.r3.corda'
ext.corda_release_version = '3.1'
ext.corda_gradle_plugins_version = '4.0.25'
..
=======
ext.kotlin_version = '1.1.4'
ext.quasar_version = '0.7.9'
Please consult the relevant release notes of the release in question. If not specified, you may assume the
versions you are currently using are still in force.
We also strongly recommend cross referencing with the :doc:`changelog` to confirm changes.
UNRELEASED
----------
<<< Fill this in >>>
* Database upgrade - Change the type of the ``checkpoint_value``.
This will address the issue that the `vacuum` function is unable to clean up deleted checkpoints as they are still referenced from the ``pg_shdepend`` table.
For Postgres:
.. sourcecode:: sql
ALTER TABLE node_checkpoints ALTER COLUMN checkpoint_value set data type bytea;
For H2:
.. sourcecode:: sql
ALTER TABLE node_checkpoints ALTER COLUMN checkpoint_value set data type VARBINARY(33554432);
* API change: ``net.corda.core.schemas.PersistentStateRef`` fields (``index`` and ``txId``) incorrectly marked as nullable are now non-nullable,
:doc:`changelog` contains the explanation.
H2 database upgrade action:
For Cordapps persisting custom entities with ``PersistentStateRef`` used as non Primary Key column, the backing table needs to be updated,
In SQL replace ``your_transaction_id``/``your_output_index`` column names with your custom names, if entity didn't used JPA ``@AttributeOverrides``
then default names are ``transaction_id`` and ``output_index``.
.. sourcecode:: sql
SELECT count(*) FROM [YOUR_PersistentState_TABLE_NAME] WHERE your_transaction_id IS NULL OR your_output_index IS NULL;
In case your table already contains rows with NULL columns, and the logic doesn't distinguish between NULL and an empty string,
all NULL column occurrences can be changed to an empty string:
.. sourcecode:: sql
UPDATE [YOUR_PersistentState_TABLE_NAME] SET your_transaction_id="" WHERE your_transaction_id IS NULL;
UPDATE [YOUR_PersistentState_TABLE_NAME] SET your_output_index="" WHERE your_output_index IS NULL;
If all rows have NON NULL ``transaction_ids`` and ``output_idx`` or you have assigned empty string values, then it's safe to update the table:
>>>>>>> 121dbec87700856679baab3995352448e8214b4e
and specifying an additional repository entry to point to the location of the Corda Enterprise distribution. As an example:

View File

@ -32,6 +32,7 @@ const val NODE_DATABASE_PREFIX = "node_"
// This class forms part of the node config and so any changes to it must be handled with care
data class DatabaseConfig(
val runMigration: Boolean = false,
val initialiseSchema: Boolean = true,
val transactionIsolationLevel: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ,
val schema: String? = null,
val exportHibernateJMXStatistics: Boolean = false,
@ -99,7 +100,8 @@ class CordaPersistence(
// Check not in read-only mode.
transaction {
check(!connection.metaData.isReadOnly) { "Database should not be readonly." }
checkCorrectAttachmentsContractsTableName(connection)
checkCorrectCheckpointTypeOnPostgres(connection)
}
}
object DataSourceConfigTag {
@ -303,4 +305,34 @@ private fun Throwable.hasSQLExceptionCause(): Boolean =
else -> cause?.hasSQLExceptionCause() ?: false
}
class CouldNotCreateDataSourceException(override val message: String?, override val cause: Throwable? = null) : Exception()
class CouldNotCreateDataSourceException(override val message: String?, override val cause: Throwable? = null) : Exception()
class DatabaseIncompatibleException(override val message: String?, override val cause: Throwable? = null) : Exception()
private fun checkCorrectAttachmentsContractsTableName(connection: Connection) {
val correctName = "NODE_ATTACHMENTS_CONTRACTS"
val incorrectV30Name = "NODE_ATTACHMENTS_CONTRACT_CLASS_NAME"
val incorrectV31Name = "NODE_ATTCHMENTS_CONTRACTS"
fun warning(incorrectName: String, version: String) = "The database contains the older table name $incorrectName instead of $correctName, see upgrade notes to migrate from Corda database version $version https://docs.corda.net/head/upgrade-notes.html."
if (!connection.metaData.getTables(null, null, correctName, null).next()) {
if (connection.metaData.getTables(null, null, incorrectV30Name, null).next()) { throw DatabaseIncompatibleException(warning(incorrectV30Name, "3.0")) }
if (connection.metaData.getTables(null, null, incorrectV31Name, null).next()) { throw DatabaseIncompatibleException(warning(incorrectV31Name, "3.1")) }
}
}
private fun checkCorrectCheckpointTypeOnPostgres(connection: Connection) {
val metaData = connection.metaData
if (metaData.getDatabaseProductName() != "PostgreSQL") {
return
}
val result = metaData.getColumns(null, null, "node_checkpoints", "checkpoint_value")
if (result.next()) {
val type = result.getString("TYPE_NAME")
if (type != "bytea") {
throw DatabaseIncompatibleException("The type of the 'checkpoint_value' table must be 'bytea', but 'oid' was found. See upgrade notes to migrate from Corda database version 3.1 https://docs.corda.net/head/upgrade-notes.html.")
}
}
}

View File

@ -66,6 +66,7 @@ class HibernateConfiguration(
// nationalised (i.e. Unicode) strings by default
val forceUnicodeForSqlServer = listOf(":oracle:", ":sqlserver:").any { jdbcUrl.contains(it, ignoreCase = true) }
enableGlobalNationalizedCharacterDataSupport(forceUnicodeForSqlServer)
return build()
}
}
@ -233,3 +234,4 @@ class HibernateConfiguration(
/** Allow Oracle database drivers ojdbc7.jar and ojdbc8.jar to deserialize classes from oracle.sql.converter package. */
fun oracleJdbcDriverSerialFilter(clazz: Class<*>): Boolean = clazz.name.startsWith("oracle.sql.converter.")

View File

@ -20,8 +20,8 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.DataSourceFactory
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions
import net.corda.node.services.config.PasswordEncryption
import net.corda.testing.core.ALICE_NAME
@ -47,6 +47,7 @@ import kotlin.test.assertFailsWith
*/
@RunWith(Parameterized::class)
class AuthDBTests : NodeBasedTest() {
companion object {
@ClassRule
@JvmField
@ -59,7 +60,7 @@ class AuthDBTests : NodeBasedTest() {
fun encFormats() = arrayOf(PasswordEncryption.NONE, PasswordEncryption.SHIRO_1_CRYPT)
}
private lateinit var node: StartedNode<Node>
private lateinit var node: StartedNodeWithInternals
private lateinit var client: CordaRPCClient
private lateinit var db: UsersDB

View File

@ -0,0 +1,70 @@
package net.corda.node.persistence
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.internal.packageName
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.Permissions
import net.corda.testMessage.Message
import net.corda.testMessage.MessageState
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.User
import org.junit.Test
import java.nio.file.Path
import java.sql.DriverManager
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class FailNodeOnNotMigratedAttachmentContractsTableNameTests {
@Test
fun `node fails when detecting table name not migrated from version 3 dot 0`() {
`node fails when not detecting compatible table name`("NODE_ATTACHMENTS_CONTRACTS", "NODE_ATTACHMENTS_CONTRACT_CLASS_NAME")
}
@Test
fun `node fails when detecting table name not migrated from version 3 dot 1`() {
`node fails when not detecting compatible table name`("NODE_ATTACHMENTS_CONTRACTS", "NODE_ATTCHMENTS_CONTRACTS")
}
private fun `node fails when not detecting compatible table name`(tableNameFromMapping: String, tableNameInDB: String) {
val user = User("mark", "dadada", setOf(Permissions.startFlow<SendMessageFlow>(), Permissions.invokeRpc("vaultQuery")))
val message = Message("Hello world!")
val baseDir: Path = driver(DriverParameters(
inMemoryDB = false,
startNodesInProcess = isQuasarAgentSpecified(),
extraCordappPackagesToScan = listOf(MessageState::class.packageName)
)) {
val (nodeName, baseDir) = {
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
val nodeName = nodeHandle.nodeInfo.singleIdentity().name
CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow()
}
nodeHandle.stop()
Pair(nodeName, nodeHandle.baseDirectory)
}()
// replace the correct table name with one from the former release
DriverManager.getConnection("jdbc:h2:file://$baseDir/persistence", "sa", "").use {
it.createStatement().execute("ALTER TABLE $tableNameFromMapping RENAME TO $tableNameInDB")
it.commit()
}
assertFailsWith(net.corda.nodeapi.internal.persistence.DatabaseIncompatibleException::class) {
val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user)).getOrThrow()
nodeHandle.stop()
}
baseDir
}
// check that the node didn't recreated the correct table matching it's entity mapping
val (hasTableFromMapping, hasTableFromDB) = DriverManager.getConnection("jdbc:h2:file://$baseDir/persistence", "sa", "").use {
Pair(it.metaData.getTables(null, null, tableNameFromMapping, null).next(),
it.metaData.getTables(null, null, tableNameInDB, null).next())
}
assertFalse(hasTableFromMapping)
assertTrue(hasTableFromDB)
}
}

View File

@ -47,7 +47,6 @@ import net.corda.testing.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.hamcrest.Matchers.instanceOf
@ -75,7 +74,7 @@ class BFTNotaryServiceTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notary: Party
private lateinit var node: StartedNode<MockNode>
private lateinit var node: StartedNode
@BeforeClass
@JvmStatic
@ -95,7 +94,7 @@ class BFTNotaryServiceTests {
IntegrationTest.globalTearDown() //Enterprise only - remote db cleanup
}
fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair<Party, StartedNode<MockNode>> {
fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair<Party, StartedNode> {
(Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists?
val replicaIds = (0 until clusterSize)
@ -237,7 +236,7 @@ class BFTNotaryServiceTests {
signatures.forEach { it.verify(txId) }
}
private fun StartedNode<MockNode>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction(
TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -16,7 +16,6 @@ import net.corda.testing.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.startFlow
import org.junit.After
import org.junit.Before
@ -59,7 +58,7 @@ class BFTSMaRtTests : IntegrationTest() {
f.getOrThrow()
}
private fun StartedNode<MockNode>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction(
TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -32,7 +32,6 @@ import net.corda.core.node.NotaryInfo
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.MySQLConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.transactions.MySQLNotaryService
@ -68,10 +67,10 @@ class MySQLNotaryServiceTests : IntegrationTest() {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var node: StartedNode<InternalMockNetwork.MockNode>
private lateinit var node: TestStartedNode
private val nodeParty: Party get() = node.info.singleIdentity()
private lateinit var notaryParty: Party
private lateinit var notaryNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var notaryNode: TestStartedNode
@Before
fun before() {
@ -247,7 +246,7 @@ class MySQLNotaryServiceTests : IntegrationTest() {
}
}
private fun issueState(node: StartedNode<InternalMockNetwork.MockNode>, notary: Party): StateAndRef<*> {
private fun issueState(node: TestStartedNode, notary: Party): StateAndRef<*> {
return node.database.transaction {
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.singleIdentity().ref(0))
val stx = node.services.signInitialTransaction(builder)

View File

@ -15,7 +15,6 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.internal.toDatabaseSchemaName
@ -126,7 +125,7 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
// HELPERS
// Helper function to restart nodes with the same host and port.
private fun startNodesWithPort(nodesToStart: List<Party>, customRetryIntervalMs: Long? = null): List<StartedNode<Node>> {
private fun startNodesWithPort(nodesToStart: List<Party>, customRetryIntervalMs: Long? = null): List<StartedNode> {
return nodesToStart.map { party ->
val configOverrides = (addressesMap[party.name]?.let { mapOf("p2pAddress" to it.toString()) } ?: emptyMap()) +
(customRetryIntervalMs?.let { mapOf("activeMQServer.bridge.retryIntervalMs" to it.toString()) } ?: emptyMap())

View File

@ -33,6 +33,7 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.driver.PortAllocation
import net.corda.testing.internal.LogHelper
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.internal.makeInternalTestDataSourceProperties
import org.hamcrest.Matchers.instanceOf
import org.junit.After
@ -164,7 +165,7 @@ class RaftTransactionCommitLogTests {
private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> {
val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build()
val address = Address(myAddress.host, myAddress.port)
val database = configureDatabase(makeInternalTestDataSourceProperties( configSupplier = { ConfigFactory.empty() }), DatabaseConfig(runMigration = true), { null }, { null }, NodeSchemaService(includeNotarySchemas = true))
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), { null }, { null }, NodeSchemaService(includeNotarySchemas = true))
databases.add(database)
val stateMachineFactory = { RaftTransactionCommitLog(database, Clock.systemUTC(), RaftUniquenessProvider.Companion::createMap) }

View File

@ -24,8 +24,7 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.nodeapi.RPCApi
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.INTERNAL_PREFIX
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NOTIFICATIONS_ADDRESS
@ -38,6 +37,7 @@ import net.corda.testing.core.singleIdentity
import net.corda.testing.internal.configureTestSSL
import net.corda.testing.internal.toDatabaseSchemaName
import net.corda.testing.node.internal.NodeBasedTest
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
@ -61,7 +61,7 @@ abstract class MQSecurityTest : NodeBasedTest() {
}
val rpcUser = User("user1", "pass", permissions = emptySet())
lateinit var alice: StartedNode<Node>
lateinit var alice: StartedNodeWithInternals
lateinit var attacker: SimpleMQClient
private val clients = ArrayList<SimpleMQClient>()

View File

@ -121,24 +121,12 @@ import net.corda.core.crypto.generateKeyPair as cryptoGenerateKeyPair
// In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the
// AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in.
abstract class AbstractNode(val configuration: NodeConfiguration,
val platformClock: CordaClock,
protected val versionInfo: VersionInfo,
protected val cordappLoader: CordappLoader,
protected val serverThread: AffinityExecutor.ServiceAffinityExecutor,
protected val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() {
private class StartedNodeImpl<out N : AbstractNode>(
override val internals: N,
override val info: NodeInfo,
override val rpcOps: CordaRPCOps,
override val notaryService: NotaryService?) : StartedNode<N> {
override val smm: StateMachineManager get() = internals.smm
override val attachments: NodeAttachmentService get() = internals.attachments
override val network: MessagingService get() = internals.network
override val database: CordaPersistence get() = internals.database
override val services: StartedNodeServices = object : StartedNodeServices, ServiceHubInternal by internals.services, FlowStarter by internals.flowStarter {}
}
abstract class AbstractNode<S : StartedNode>(val configuration: NodeConfiguration,
val platformClock: CordaClock,
protected val versionInfo: VersionInfo,
protected val cordappLoader: CordappLoader,
protected val serverThread: AffinityExecutor.ServiceAffinityExecutor,
protected val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() {
protected abstract val log: Logger
@ -205,7 +193,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
val services = ServiceHubInternalImpl().tokenize()
@Suppress("LeakingThis")
val smm = makeStateMachineManager()
private val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory)
protected val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory)
private val schedulerService = NodeSchedulerService(
platformClock,
database,
@ -243,7 +231,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
/** Set to non-null once [start] has been successfully called. */
open val started get() = _started
@Volatile
private var _started: StartedNode<AbstractNode>? = null
private var _started: StartedNode? = null
private fun <T : Any> T.tokenize(): T {
tokenizableServices?.add(this) ?: throw IllegalStateException("The tokenisable services list has already been finialised")
@ -305,7 +293,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
}
}
open fun start(): StartedNode<AbstractNode> {
open fun start(): S {
check(started == null) { "Node has already been started" }
if (configuration.devMode) {
@ -401,10 +389,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
schedulerService.start()
StartedNodeImpl(this@AbstractNode, nodeInfo, rpcOps, notaryService).also { _started = it }
createStartedNode(nodeInfo, rpcOps, notaryService).also { _started = it }
}
}
/** Subclasses must override this to create a [StartedNode] of the desired type, using the provided machinery. */
abstract fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): S
private fun verifyCheckpointsCompatible(tokenizableServices: List<Any>) {
try {
CheckpointVerifier.verifyCheckpointsCompatible(checkpointStorage, cordappProvider.cordapps, versionInfo.platformVersion, services, tokenizableServices)
@ -664,7 +655,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
}
}
internal fun <T : FlowLogic<*>> registerInitiatedFlow(smm: StateMachineManager, initiatedFlowClass: Class<T>): Observable<T> {
protected fun <T : FlowLogic<*>> registerInitiatedFlow(smm: StateMachineManager, initiatedFlowClass: Class<T>): Observable<T> {
return registerInitiatedFlowInternal(smm, initiatedFlowClass, track = true)
}
@ -700,11 +691,11 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
return observable
}
internal fun <F : FlowLogic<*>> internalRegisterFlowFactory(smm: StateMachineManager,
initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> {
protected fun <F : FlowLogic<*>> internalRegisterFlowFactory(smm: StateMachineManager,
initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> {
val observable = if (track) {
smm.changes.filter { it is StateMachineManager.Change.Add }.map { it.logic }.ofType(initiatedFlowClass)
} else {
@ -1003,7 +994,7 @@ internal fun logVendorString(database: CordaPersistence, log: Logger) {
}
// TODO Move this into its own file
internal class FlowStarterImpl(private val smm: StateMachineManager, private val flowLogicRefFactory: FlowLogicRefFactory) : FlowStarter {
class FlowStarterImpl(private val smm: StateMachineManager, private val flowLogicRefFactory: FlowLogicRefFactory) : FlowStarter {
override fun <T> startFlow(event: ExternalEvent.ExternalStartFlowEvent<T>): CordaFuture<FlowStateMachine<T>> {
smm.deliverExternalEvent(event)
return event.future
@ -1054,11 +1045,9 @@ fun configureDatabase(hikariProperties: Properties,
databaseConfig: DatabaseConfig,
wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
wellKnownPartyFromAnonymous: (AbstractParty) -> Party?,
schemaService: SchemaService = NodeSchemaService()): CordaPersistence {
val persistence = createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService)
persistence.hikariStart(hikariProperties, databaseConfig, schemaService)
return persistence
}
schemaService: SchemaService = NodeSchemaService()): CordaPersistence =
createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService)
.apply { hikariStart(hikariProperties, databaseConfig, schemaService) }
fun createCordaPersistence(databaseConfig: DatabaseConfig,
wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
@ -1089,7 +1078,8 @@ fun CordaPersistence.hikariStart(hikariProperties: Properties, databaseConfig: D
when {
ex is HikariPool.PoolInitializationException -> throw CouldNotCreateDataSourceException("Could not connect to the database. Please check your JDBC connection URL, or the connectivity to the database.", ex)
ex.cause is ClassNotFoundException -> throw CouldNotCreateDataSourceException("Could not find the database driver class. Please add it to the 'drivers' folder. See: https://docs.corda.net/corda-configuration-file.html")
ex is DatabaseIncompatibleException -> throw ex
else -> throw CouldNotCreateDataSourceException("Could not create the DataSource: ${ex.message}", ex)
}
}
}
}

View File

@ -172,7 +172,7 @@ D""".trimStart()
}
}
override fun start(): StartedNode<Node> {
override fun start(): StartedNode {
val started = super.start()
registerOptionalMetricsReporter(configuration, started.services.monitoringService.metrics)
return started

View File

@ -13,6 +13,7 @@ package net.corda.node.internal
import com.codahale.metrics.JmxReporter
import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationScheme
import net.corda.core.concurrent.CordaFuture
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.Emoji
@ -20,7 +21,11 @@ import net.corda.core.internal.concurrent.openFuture
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.div
import net.corda.core.internal.errors.AddressBindingException
import net.corda.core.internal.uncheckedCast
import net.corda.core.internal.notary.NotaryService
import net.corda.node.services.api.StartedNodeServices
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.RPCOps
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
@ -43,6 +48,8 @@ import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoServerSerializationScheme
import net.corda.node.services.Permissions
import net.corda.node.services.api.FlowStarter
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.SecurityConfiguration
import net.corda.node.services.config.shouldInitCrashShell
@ -70,6 +77,16 @@ import java.time.Clock
import java.util.concurrent.atomic.AtomicInteger
import javax.management.ObjectName
import kotlin.system.exitProcess
import net.corda.node.services.persistence.NodeAttachmentService
/**
* A version of [StartedNode] which exposes its [Node] internals.
*
* Although this is the type of [StartedNode] created by [Node], it is not explicitly provided
* and should not ordinarily be used (the code that _does_ use it obtains it via a cast).
*/
interface StartedNodeWithInternals : StartedNode {
val internals: Node
}
/**
* A Node manages a standalone server that takes part in the P2P network. It creates the services found in [ServiceHub],
@ -81,7 +98,7 @@ open class Node(configuration: NodeConfiguration,
versionInfo: VersionInfo,
private val initialiseSerialization: Boolean = true,
cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo)
) : AbstractNode(
) : AbstractNode<StartedNode>(
configuration,
createClock(configuration),
versionInfo,
@ -89,6 +106,38 @@ open class Node(configuration: NodeConfiguration,
// Under normal (non-test execution) it will always be "1"
AffinityExecutor.ServiceAffinityExecutor("Node thread-${sameVmNodeCounter.incrementAndGet()}", 1)
) {
/** The actual [StartedNode] implementation created by this [AbstractNode]. */
private class StartedNodeWithInternalsImpl(
override val internals: Node,
override val attachments: NodeAttachmentService,
override val network: MessagingService,
override val services: StartedNodeServices,
override val info: NodeInfo,
override val smm: StateMachineManager,
override val database: CordaPersistence,
override val rpcOps: CordaRPCOps,
override val notaryService: NotaryService?) : StartedNodeWithInternals {
override fun dispose() = internals.stop()
override fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>) =
internals.registerInitiatedFlow(smm, initiatedFlowClass)
}
override fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): StartedNode =
StartedNodeWithInternalsImpl(
this,
attachments,
network,
object : StartedNodeServices, ServiceHubInternal by services, FlowStarter by flowStarter { },
nodeInfo,
smm,
database,
rpcOps,
notaryService
)
companion object {
private val staticLog = contextLogger()
var renderBasicInfoToConsole = true
@ -379,9 +428,9 @@ open class Node(configuration: NodeConfiguration,
return super.generateAndSaveNodeInfo()
}
override fun start(): StartedNode<Node> {
override fun start(): StartedNode {
initialiseSerialization()
val started: StartedNode<Node> = uncheckedCast(super.start())
val started: StartedNode = super.start()
nodeReadyFuture.thenMatch({
serverThread.execute {
// Begin exporting our own metrics via JMX. These can be monitored using any agent, e.g. Jolokia:
@ -454,4 +503,4 @@ open class Node(configuration: NodeConfiguration,
log.info("Shutdown complete")
}
}
}

View File

@ -39,6 +39,7 @@ import net.corda.node.utilities.registration.UnableToRegisterNodeWithDoormanExce
import net.corda.node.utilities.saveToKeyStore
import net.corda.node.utilities.saveToTrustStore
import net.corda.nodeapi.internal.addShutdownHook
import net.corda.nodeapi.internal.persistence.DatabaseIncompatibleException
import net.corda.nodeapi.internal.config.UnknownConfigurationKeysException
import net.corda.nodeapi.internal.persistence.DatabaseMigrationException
import net.corda.nodeapi.internal.persistence.oracleJdbcDriverSerialFilter
@ -191,6 +192,10 @@ open class NodeStartup(val args: Array<String>) {
} catch (e: NetworkParametersReader.Error) {
logger.error(e.message)
return false
} catch (e: DatabaseIncompatibleException) {
e.message?.let { Node.printWarning(it) }
logger.error(e.message)
return false
} catch (e: Exception) {
if (e is Errors.NativeIoException && e.message?.contains("Address already in use") == true) {
logger.error("One of the ports required by the Corda node is already in use.")
@ -338,15 +343,16 @@ open class NodeStartup(val args: Array<String>) {
}
val startedNode = node.start()
logLoadedCorDapps(startedNode.services.cordappProvider.cordapps)
startedNode.internals.nodeReadyFuture.thenMatch({
logLoadedCorDapps(node.services.cordappProvider.cordapps)
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name })
node.nodeReadyFuture.thenMatch({
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation
Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec")
// Don't start the shell if there's no console attached.
if (conf.shouldStartLocalShell()) {
startedNode.internals.startupComplete.then {
node.startupComplete.then {
try {
InteractiveShell.runLocalShell({ startedNode.dispose() })
} catch (e: Throwable) {
@ -361,7 +367,7 @@ open class NodeStartup(val args: Array<String>) {
{ th ->
logger.error("Unexpected exception during registration", th)
})
startedNode.internals.run()
node.run()
}
protected open fun logStartupInfo(versionInfo: VersionInfo, cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) {

View File

@ -10,13 +10,16 @@
package net.corda.node.internal
import com.google.common.annotations.VisibleForTesting
interface NodeUniqueIdProvider {
val value: String
}
// this is stubbed because we still do not support clustered node setups.
// the moment we will, this will have to be changed to return a value unique for each physical node.
internal object StubbedNodeUniqueIdProvider : NodeUniqueIdProvider {
@VisibleForTesting
object StubbedNodeUniqueIdProvider : NodeUniqueIdProvider {
// TODO implement to return a value unique for each physical node when we will support clustered node setups.
override val value: String = "NABOB"

View File

@ -23,8 +23,7 @@ import net.corda.node.services.statemachine.StateMachineManager
import net.corda.nodeapi.internal.persistence.CordaPersistence
import rx.Observable
interface StartedNode<out N : AbstractNode> {
val internals: N
interface StartedNode {
val services: StartedNodeServices
val info: NodeInfo
val smm: StateMachineManager
@ -34,20 +33,12 @@ interface StartedNode<out N : AbstractNode> {
val rpcOps: CordaRPCOps
val notaryService: NotaryService?
fun dispose() = internals.stop()
fun dispose()
/**
* Use this method to register your initiated flows in your tests. This is automatically done by the node when it
* starts up for all [FlowLogic] classes it finds which are annotated with [InitiatedBy].
* @return An [Observable] of the initiated flows started by counterparties.
*/
fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>) = internals.registerInitiatedFlow(smm, initiatedFlowClass)
@VisibleForTesting
fun <F : FlowLogic<*>> internalRegisterFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> {
return internals.internalRegisterFlowFactory(smm, initiatingFlowClass, flowFactory, initiatedFlowClass, track)
}
fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T>
}

View File

@ -51,7 +51,6 @@ import net.corda.testing.core.expectEvents
import net.corda.testing.core.sequence
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.testActor
import org.apache.commons.io.IOUtils
@ -82,7 +81,7 @@ class CordaRPCOpsImplTest {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var alice: Party
private lateinit var notary: Party
private lateinit var rpc: CordaRPCOps

View File

@ -54,7 +54,7 @@ class NodeTest {
}
}
private fun AbstractNode.generateNodeInfo(): NodeInfo {
private fun Node.generateNodeInfo(): NodeInfo {
assertNull(nodeInfoFile())
generateAndSaveNodeInfo()
val path = nodeInfoFile()!!

View File

@ -323,7 +323,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
// of gets and puts.
private fun makeNodeWithTracking(name: CordaX500Name): StartedNode<InternalMockNetwork.MockNode> {
private fun makeNodeWithTracking(name: CordaX500Name): StartedNode {
// Create a node in the mock network ...
return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args, cordappLoader ->
if (cordappLoader != null) {
@ -553,8 +553,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun runBuyerAndSeller(notary: Party,
buyer: Party,
sellerNode: StartedNode<InternalMockNetwork.MockNode>,
buyerNode: StartedNode<InternalMockNetwork.MockNode>,
sellerNode: StartedNode,
buyerNode: StartedNode,
assetToSell: StateAndRef<OwnableState>): RunResult {
val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
@ -648,10 +648,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun insertFakeTransactions(
wtxToSign: List<WireTransaction>,
node: StartedNode<*>,
node: StartedNode,
identity: Party,
notaryNode: StartedNode<*>,
vararg extraSigningNodes: StartedNode<*>): Map<SecureHash, SignedTransaction> {
notaryNode: StartedNode,
vararg extraSigningNodes: StartedNode): Map<SecureHash, SignedTransaction> {
val notaryParty = mockNet.defaultNotaryIdentity
val signed = wtxToSign.map {
val id = it.id

View File

@ -44,8 +44,8 @@ import kotlin.test.fail
class ScheduledFlowsDrainingModeTest {
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var bobNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var bobNode: StartedNode
private lateinit var notary: Party
private lateinit var alice: Party
private lateinit var bob: Party

View File

@ -75,7 +75,7 @@ class FinalityHandlerTest {
assertThat(bob.getTransaction(finalisedTx.id)).isNull()
}
private fun StartedNode<*>.assertFlowSentForObservation(runId: StateMachineRunId) {
private fun StartedNode.assertFlowSentForObservation(runId: StateMachineRunId) {
val keptInForObservation = smm.flowHospital
.track()
.let { it.updates.startWith(it.snapshot) }
@ -86,7 +86,7 @@ class FinalityHandlerTest {
assertThat(keptInForObservation.by).contains(StaffedFlowHospital.FinalityDoctor)
}
private fun StartedNode<*>.getTransaction(id: SecureHash): SignedTransaction? {
private fun StartedNode.getTransaction(id: SecureHash): SignedTransaction? {
return database.transaction {
services.validatedTransactions.getTransaction(id)
}

View File

@ -46,10 +46,7 @@ import net.corda.testing.internal.GlobalDatabaseRule
import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.startFlow
import net.corda.testing.node.internal.*
import org.junit.Before
import org.junit.ClassRule
import org.junit.Test
@ -65,9 +62,9 @@ class TimedFlowTestRule(val clusterSize: Int) : ExternalResource() {
lateinit var mockNet: InternalMockNetwork
lateinit var notary: Party
lateinit var node: StartedNode<InternalMockNetwork.MockNode>
lateinit var node: TestStartedNode
private fun startClusterAndNode(mockNet: InternalMockNetwork): Pair<Party, StartedNode<InternalMockNetwork.MockNode>> {
private fun startClusterAndNode(mockNet: InternalMockNetwork): Pair<Party, TestStartedNode> {
val replicaIds = (0 until clusterSize)
val notaryIdentity = DevIdentityGenerator.generateDistributedNotaryCompositeIdentity(
replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) },
@ -187,7 +184,7 @@ class TimedFlowTests {
}
}
private fun StartedNode<InternalMockNetwork.MockNode>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction(
TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -35,7 +35,6 @@ import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.After
@ -53,8 +52,8 @@ class ScheduledFlowTests {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var bobNode: StartedNode
private lateinit var notary: Party
private lateinit var alice: Party
private lateinit var bob: Party

View File

@ -21,8 +21,8 @@ import net.corda.core.internal.executeAsync
import net.corda.core.node.AppServiceHub
import net.corda.core.node.services.CordaService
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.node.internal.StartedNode
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.startFlow
import org.junit.After
@ -34,7 +34,7 @@ import kotlin.test.assertFailsWith
class FlowAsyncOperationTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: TestStartedNode
@Before
fun setup() {
mockNet = InternalMockNetwork(

View File

@ -46,7 +46,6 @@ import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType
@ -67,8 +66,8 @@ class FlowFrameworkTests {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: TestStartedNode
private lateinit var alice: Party
private lateinit var bob: Party
private lateinit var notaryIdentity: Party
@ -456,7 +455,7 @@ class FlowFrameworkTests {
private val normalEnd = ExistingSessionMessage(SessionId(0), EndSessionMessage) // NormalSessionEnd(0)
private fun StartedNode<*>.sendSessionMessage(message: SessionMessage, destination: Party) {
private fun StartedNode.sendSessionMessage(message: SessionMessage, destination: Party) {
services.networkService.apply {
val address = getAddressOfParty(PartyInfo.SingleNode(destination, emptyList()))
send(createMessage(FlowMessagingImpl.sessionTopic, message.serialize().bytes), address)
@ -478,9 +477,9 @@ class FlowFrameworkTripartyTests {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var charlieNode: StartedNode<MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: TestStartedNode
private lateinit var charlieNode: TestStartedNode
private lateinit var alice: Party
private lateinit var bob: Party
private lateinit var charlie: Party
@ -629,7 +628,7 @@ class FlowFrameworkTripartyTests {
assertThat(receivedSessionMessages).containsExactly(*expected)
}
private fun assertSessionTransfers(node: StartedNode<MockNode>, vararg expected: SessionTransfer): List<SessionTransfer> {
private fun assertSessionTransfers(node: TestStartedNode, vararg expected: SessionTransfer): List<SessionTransfer> {
val actualForNode = receivedSessionMessages.filter { it.from == node.internals.id || it.to == node.network.myAddress }
assertThat(actualForNode).containsExactly(*expected)
return actualForNode
@ -646,8 +645,8 @@ class FlowFrameworkPersistenceTests {
private lateinit var mockNet: InternalMockNetwork
private val receivedSessionMessages = ArrayList<SessionTransfer>()
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: TestStartedNode
private lateinit var notaryIdentity: Party
private lateinit var alice: Party
private lateinit var bob: Party
@ -759,7 +758,7 @@ class FlowFrameworkPersistenceTests {
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//region Helpers
private inline fun <reified P : FlowLogic<*>> StartedNode<MockNode>.restartAndGetRestoredFlow(): P {
private inline fun <reified P : FlowLogic<*>> TestStartedNode.restartAndGetRestoredFlow(): P {
val newNode = mockNet.restartNode(this)
newNode.internals.acceptableLiveFiberCountOnStop = 1
mockNet.runNetwork()
@ -770,7 +769,7 @@ class FlowFrameworkPersistenceTests {
assertThat(receivedSessionMessages).containsExactly(*expected)
}
private fun assertSessionTransfers(node: StartedNode<MockNode>, vararg expected: SessionTransfer): List<SessionTransfer> {
private fun assertSessionTransfers(node: TestStartedNode, vararg expected: SessionTransfer): List<SessionTransfer> {
val actualForNode = receivedSessionMessages.filter { it.from == node.internals.id || it.to == node.network.myAddress }
assertThat(actualForNode).containsExactly(*expected)
return actualForNode
@ -785,7 +784,7 @@ class FlowFrameworkPersistenceTests {
private fun sessionConfirm(flowVersion: Int = 1) = ExistingSessionMessage(SessionId(0), ConfirmSessionMessage(SessionId(0), FlowInfo(flowVersion, "")))
private inline fun <reified P : FlowLogic<*>> StartedNode<*>.getSingleFlow(): Pair<P, CordaFuture<*>> {
private inline fun <reified P : FlowLogic<*>> StartedNode.getSingleFlow(): Pair<P, CordaFuture<*>> {
return smm.findStateMachines(P::class.java).single()
}
@ -819,8 +818,8 @@ private fun Observable<MessageTransfer>.toSessionTransfers(): Observable<Session
private fun errorMessage(errorResponse: FlowException? = null) = ExistingSessionMessage(SessionId(0), ErrorSessionMessage(errorResponse, 0))
private infix fun StartedNode<MockNode>.sent(message: SessionMessage): Pair<Int, SessionMessage> = Pair(internals.id, message)
private infix fun Pair<Int, SessionMessage>.to(node: StartedNode<*>): SessionTransfer = SessionTransfer(first, second, node.network.myAddress)
private infix fun TestStartedNode.sent(message: SessionMessage): Pair<Int, SessionMessage> = Pair(internals.id, message)
private infix fun Pair<Int, SessionMessage>.to(node: StartedNode): SessionTransfer = SessionTransfer(first, second, node.network.myAddress)
private data class SessionTransfer(val from: Int, val message: SessionMessage, val to: MessageRecipients) {
val isPayloadTransfer: Boolean get() =
@ -829,7 +828,7 @@ private data class SessionTransfer(val from: Int, val message: SessionMessage, v
override fun toString(): String = "$from sent $message to $to"
}
private inline fun <reified P : FlowLogic<*>> StartedNode<*>.registerFlowFactory(
private inline fun <reified P : FlowLogic<*>> TestStartedNode.registerFlowFactory(
initiatingFlowClass: KClass<out FlowLogic<*>>,
initiatedFlowVersion: Int = 1,
noinline flowFactory: (FlowSession) -> P): CordaFuture<P> {

View File

@ -27,8 +27,8 @@ import kotlin.test.assertEquals
class IdempotentFlowTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var nodeA: StartedNode<InternalMockNetwork.MockNode>
private lateinit var nodeB: StartedNode<InternalMockNetwork.MockNode>
private lateinit var nodeA: StartedNode
private lateinit var nodeB: StartedNode
companion object {
val executionCounter = AtomicInteger(0)

View File

@ -18,10 +18,10 @@ import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.nodeapi.internal.persistence.contextTransaction
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.MessagingServiceSpy
import net.corda.testing.node.internal.newContext
import net.corda.testing.node.internal.setMessagingServiceSpy
import net.corda.testing.node.internal.*
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.hibernate.exception.ConstraintViolationException
@ -38,8 +38,8 @@ import kotlin.test.assertNull
class RetryFlowMockTest {
private lateinit var mockNet: InternalMockNetwork
private lateinit var nodeA: StartedNode<MockNode>
private lateinit var nodeB: StartedNode<MockNode>
private lateinit var nodeA: TestStartedNode
private lateinit var nodeB: TestStartedNode
@Before
fun start() {
@ -53,7 +53,7 @@ class RetryFlowMockTest {
KeepSendingFlow.count.set(0)
}
private fun <T> StartedNode<MockNode>.startFlow(logic: FlowLogic<T>): CordaFuture<T> {
private fun <T> StartedNode.startFlow(logic: FlowLogic<T>): CordaFuture<T> {
return this.services.startFlow(logic, this.services.newContext()).flatMap { it.resultFuture }
}

View File

@ -37,7 +37,7 @@ import kotlin.test.assertFailsWith
class NotaryServiceTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notaryServices: ServiceHub
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var notary: Party
private lateinit var alice: Party
@ -65,7 +65,7 @@ class NotaryServiceTests {
internal companion object {
/** This is used by both [NotaryServiceTests] and [ValidatingNotaryServiceTests]. */
fun notariseWithTooManyInputs(node: StartedNode<InternalMockNetwork.MockNode>, party: Party, notary: Party, network: InternalMockNetwork) {
fun notariseWithTooManyInputs(node: StartedNode, party: Party, notary: Party, network: InternalMockNetwork) {
val stx = generateTransaction(node, party, notary)
val future = node.services.startFlow(DummyClientFlow(stx, notary)).resultFuture
@ -73,7 +73,7 @@ class NotaryServiceTests {
assertFailsWith<NotaryException> { future.getOrThrow() }
}
private fun generateTransaction(node: StartedNode<InternalMockNetwork.MockNode>, party: Party, notary: Party): SignedTransaction {
private fun generateTransaction(node: StartedNode, party: Party, notary: Party): SignedTransaction {
val txHash = SecureHash.randomSHA256()
val inputs = (1..10_005).map { StateRef(txHash, it) }
val tx = NotaryChangeTransactionBuilder(inputs, notary, party).build()

View File

@ -37,7 +37,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.issueInvalidState
import net.corda.node.services.messaging.Message
import net.corda.node.services.statemachine.InitialSessionMessage
@ -53,6 +52,7 @@ import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.MessagingServiceSpy
import net.corda.testing.node.internal.setMessagingServiceSpy
import net.corda.testing.node.internal.startFlow
import net.corda.testing.node.internal.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
@ -66,8 +66,8 @@ import kotlin.test.assertTrue
class ValidatingNotaryServiceTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notaryNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var notaryNode: TestStartedNode
private lateinit var aliceNode: TestStartedNode
private lateinit var notary: Party
private lateinit var alice: Party

View File

@ -19,10 +19,10 @@ import net.corda.core.node.services.trackBy
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.testing.core.*
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.startFlow
import org.junit.After
@ -33,9 +33,9 @@ import kotlin.test.assertEquals
class CashIssueAndPaymentFlowTests {
private lateinit var mockNet: InternalMockNetwork
private val ref = OpaqueBytes.of(0x01)
private lateinit var bankOfCordaNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var bankOfCordaNode: TestStartedNode
private lateinit var bankOfCorda: Party
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var notary: Party
@Before

View File

@ -19,10 +19,10 @@ import net.corda.core.node.services.trackBy
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.testing.core.*
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.startFlow
import org.junit.After
@ -42,9 +42,9 @@ class CashIssueAndPayNoSelectionTests(private val anonymous: Boolean) {
private lateinit var mockNet: InternalMockNetwork
private val ref = OpaqueBytes.of(0x01)
private lateinit var bankOfCordaNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var bankOfCordaNode: TestStartedNode
private lateinit var bankOfCorda: Party
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var notary: Party
@Before

View File

@ -19,10 +19,10 @@ import net.corda.core.node.services.trackBy
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.testing.core.*
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.startFlow
import org.junit.After
@ -35,9 +35,9 @@ class CashPaymentFlowTests {
private lateinit var mockNet: InternalMockNetwork
private val initialBalance = 2000.DOLLARS
private val ref = OpaqueBytes.of(0x01)
private lateinit var bankOfCordaNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var bankOfCordaNode: TestStartedNode
private lateinit var bankOfCorda: Party
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: TestStartedNode
@Before
fun start() {

View File

@ -49,7 +49,6 @@ import net.corda.core.utilities.days
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.toNonEmptySet
import net.corda.core.utilities.unwrap
import net.corda.node.internal.StartedNode
import net.corda.node.services.api.CheckpointStorage
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.node.services.api.WritableTransactionStorage
@ -335,7 +334,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
// of gets and puts.
private fun makeNodeWithTracking(
name: CordaX500Name): StartedNode<InternalMockNetwork.MockNode> {
name: CordaX500Name): TestStartedNode {
// Create a node in the mock network ...
return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args, _ ->
object : InternalMockNetwork.MockNode(args) {
@ -556,8 +555,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun runBuyerAndSeller(notary: Party,
buyer: Party,
sellerNode: StartedNode<InternalMockNetwork.MockNode>,
buyerNode: StartedNode<InternalMockNetwork.MockNode>,
sellerNode: TestStartedNode,
buyerNode: TestStartedNode,
assetToSell: StateAndRef<OwnableState>): RunResult {
val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
@ -651,10 +650,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun insertFakeTransactions(
wtxToSign: List<WireTransaction>,
node: StartedNode<*>,
node: TestStartedNode,
identity: Party,
notaryNode: StartedNode<*>,
vararg extraSigningNodes: StartedNode<*>): Map<SecureHash, SignedTransaction> {
notaryNode: TestStartedNode,
vararg extraSigningNodes: TestStartedNode): Map<SecureHash, SignedTransaction> {
val notaryParty = mockNet.defaultNotaryIdentity
val signed = wtxToSign.map {
val id = it.id

View File

@ -14,8 +14,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.persistence.CordaPersistence
@ -66,7 +65,7 @@ data class InProcessImpl(
override val useHTTPS: Boolean,
private val nodeThread: Thread,
private val onStopCallback: () -> Unit,
private val node: StartedNode<Node>
private val node: StartedNodeWithInternals
) : InProcess, NodeHandleInternal {
val database: CordaPersistence get() = node.database
override val services: StartedNodeServices get() = node.services

View File

@ -20,7 +20,6 @@ import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
import net.corda.core.node.ServiceHub
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.DUMMY_NOTARY_NAME
@ -138,9 +137,9 @@ class UnstartedMockNode private constructor(private val node: InternalMockNetwor
}
/** A class that represents a started mock node for testing. */
class StartedMockNode private constructor(private val node: StartedNode<InternalMockNetwork.MockNode>) {
class StartedMockNode private constructor(private val node: TestStartedNode) {
companion object {
internal fun create(node: StartedNode<InternalMockNetwork.MockNode>): StartedMockNode {
internal fun create(node: TestStartedNode): StartedMockNode {
return StartedMockNode(node)
}
}

View File

@ -32,7 +32,7 @@ import net.corda.core.utilities.*
import net.corda.node.NodeRegistrationOption
import net.corda.node.VersionInfo
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions
import net.corda.node.services.config.*
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
@ -821,7 +821,7 @@ class DriverDSLImpl(
private fun startInProcessNode(
executorService: ScheduledExecutorService,
config: NodeConfig
): CordaFuture<Pair<StartedNode<Node>, Thread>> {
): CordaFuture<Pair<StartedNodeWithInternals, Thread>> {
return executorService.fork {
log.info("Starting in-process Node ${config.corda.myLegalName.organisation}")
if (!(ManagementFactory.getRuntimeMXBean().inputArguments.any { it.contains("quasar") })) {
@ -830,9 +830,10 @@ class DriverDSLImpl(
// Write node.conf
writeConfig(config.corda.baseDirectory, "node.conf", config.typesafe.toNodeOnly())
// TODO pass the version in?
val node = InProcessNode(config.corda, MOCK_VERSION_INFO).start()
val internals = InProcessNode(config.corda, MOCK_VERSION_INFO)
val node = internals.start() as StartedNodeWithInternals
val nodeThread = thread(name = config.corda.myLegalName.organisation) {
node.internals.run()
internals.run()
}
node to nodeThread
}.flatMap { nodeAndThread ->

View File

@ -18,10 +18,13 @@ import net.corda.core.DoNotImplement
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.*
import net.corda.core.internal.notary.NotaryService
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.MessageRecipients
import net.corda.core.messaging.RPCOps
import net.corda.core.messaging.SingleMessageRecipient
@ -34,12 +37,18 @@ import net.corda.core.utilities.*
import net.corda.node.VersionInfo
import net.corda.node.cordapp.CordappLoader
import net.corda.node.internal.AbstractNode
import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.node.internal.cordapp.JarScanningCordappLoader
import net.corda.node.services.api.FlowStarter
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.*
import net.corda.node.services.keys.E2ETestKeyManagementService
import net.corda.node.services.keys.KeyManagementServiceInternal
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.BFTSMaRt
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
@ -47,6 +56,7 @@ import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.driver.TestCorDapp
@ -56,6 +66,7 @@ import net.corda.testing.internal.testThreadFactory
import net.corda.testing.node.*
import org.apache.activemq.artemis.utils.ReusableLatch
import org.apache.sshd.common.util.security.SecurityUtils
import rx.Observable
import rx.Scheduler
import rx.internal.schedulers.CachedThreadScheduler
import java.math.BigInteger
@ -69,7 +80,7 @@ import java.util.concurrent.atomic.AtomicInteger
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")
fun StartedNode<InternalMockNetwork.MockNode>.pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? {
fun TestStartedNode.pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? {
return (network as InternalMockMessagingService).pumpReceive(block)
}
@ -98,6 +109,18 @@ data class InternalMockNodeParameters(
)
}
/**
* A [StartedNode] which exposes its internal [InternalMockNetwork.MockNode] for testing.
*/
interface TestStartedNode : StartedNode {
val internals: InternalMockNetwork.MockNode
fun <F : FlowLogic<*>> internalRegisterFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F>
}
open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParameters(),
val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
val threadPerNode: Boolean = defaultParameters.threadPerNode,
@ -146,13 +169,13 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
* Returns the list of nodes started by the network. Each notary specified when the network is constructed ([notarySpecs]
* parameter) maps 1:1 to the notaries returned by this list.
*/
val notaryNodes: List<StartedNode<MockNode>>
val notaryNodes: List<TestStartedNode>
/**
* Returns the single notary node on the network. Throws if there are none or more than one.
* @see notaryNodes
*/
val defaultNotaryNode: StartedNode<MockNode>
val defaultNotaryNode: TestStartedNode
get() {
return when (notaryNodes.size) {
0 -> throw IllegalStateException("There are no notaries defined on the network")
@ -223,7 +246,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
@VisibleForTesting
internal open fun createNotaries(): List<StartedNode<MockNode>> {
internal open fun createNotaries(): List<TestStartedNode> {
return notarySpecs.map { (name, validating) ->
createNode(InternalMockNodeParameters(legalName = name, configOverrides = {
doReturn(NotaryConfig(validating)).whenever(it).notary
@ -240,7 +263,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
}
open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories)) : AbstractNode(
open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories)) : AbstractNode<TestStartedNode>(
args.config,
TestClock(Clock.systemUTC()),
args.version,
@ -248,6 +271,45 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
args.network.getServerThread(args.id),
args.network.busyLatch
) {
/** The actual [StartedNode] implementation created by this node */
private class TestStartedNodeImpl(
override val internals: MockNode,
override val attachments: NodeAttachmentService,
override val network: MessagingService,
override val services: StartedNodeServices,
override val info: NodeInfo,
override val smm: StateMachineManager,
override val database: CordaPersistence,
override val rpcOps: CordaRPCOps,
override val notaryService: NotaryService?) : TestStartedNode {
override fun <F : FlowLogic<*>> internalRegisterFlowFactory(
initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> =
internals.internalRegisterFlowFactory(smm, initiatingFlowClass, flowFactory, initiatedFlowClass, track)
override fun dispose() = internals.stop()
override fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T> =
internals.registerInitiatedFlow(smm, initiatedFlowClass)
}
override fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): TestStartedNode =
TestStartedNodeImpl(
this,
attachments,
network,
object : StartedNodeServices, ServiceHubInternal by services, FlowStarter by flowStarter { },
nodeInfo,
smm,
database,
rpcOps,
notaryService
)
companion object {
private val staticLog = contextLogger()
}
@ -268,16 +330,14 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
}
override val started: StartedNode<MockNode>? get() = uncheckedCast(super.started)
override val started: TestStartedNode? get() = uncheckedCast(super.started)
override fun start(): StartedNode<MockNode> {
override fun start(): TestStartedNode {
mockNet.networkParametersCopier.install(configuration.baseDirectory)
val started: StartedNode<MockNode> = uncheckedCast(super.start())
advertiseNodeToNetwork(started)
return started
return super.start().also { advertiseNodeToNetwork(it) }
}
private fun advertiseNodeToNetwork(newNode: StartedNode<MockNode>) {
private fun advertiseNodeToNetwork(newNode: TestStartedNode) {
mockNet.nodes
.mapNotNull { it.started }
.forEach { existingNode ->
@ -374,20 +434,20 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
return createUnstartedNode(parameters, defaultFactory)
}
fun <N : MockNode> createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> N): N {
fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): MockNode {
return createNodeImpl(parameters, nodeFactory, false)
}
fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters()): StartedNode<MockNode> {
fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters()): TestStartedNode {
return createNode(parameters, defaultFactory)
}
/** Like the other [createNode] but takes a [nodeFactory] and propagates its [MockNode] subtype. */
fun <N : MockNode> createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> N): StartedNode<N> {
fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): TestStartedNode {
return uncheckedCast(createNodeImpl(parameters, nodeFactory, true).started)!!
}
private fun <N : MockNode> createNodeImpl(parameters: InternalMockNodeParameters, nodeFactory: (MockNodeArgs, CordappLoader?) -> N, start: Boolean): N {
private fun createNodeImpl(parameters: InternalMockNodeParameters, nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode, start: Boolean): MockNode {
val id = parameters.forcedID ?: nextNodeId++
val config = mockNodeConfiguration().also {
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
@ -410,7 +470,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
return node
}
fun <N : MockNode> restartNode(node: StartedNode<N>, nodeFactory: (MockNodeArgs, CordappLoader?) -> N): StartedNode<N> {
fun restartNode(node: TestStartedNode, nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): TestStartedNode {
node.internals.disableDBCloseOnStop()
node.dispose()
return createNode(
@ -419,7 +479,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
)
}
fun restartNode(node: StartedNode<MockNode>): StartedNode<MockNode> = restartNode(node, defaultFactory)
fun restartNode(node: TestStartedNode): TestStartedNode = restartNode(node, defaultFactory)
fun baseDirectory(nodeId: Int): Path = testDirectory / "nodes/$nodeId"
@ -445,7 +505,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
@JvmOverloads
fun createPartyNode(legalName: CordaX500Name? = null): StartedNode<MockNode> {
fun createPartyNode(legalName: CordaX500Name? = null): TestStartedNode {
return createNode(InternalMockNodeParameters(legalName = legalName))
}
@ -486,7 +546,7 @@ open class MessagingServiceSpy(val messagingService: MessagingService) : Messagi
/**
* Attach a [MessagingServiceSpy] to the [InternalMockNetwork.MockNode] allowing interception and modification of messages.
*/
fun StartedNode<InternalMockNetwork.MockNode>.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
fun TestStartedNode.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
internals.setMessagingServiceSpy(messagingServiceSpy)
}
@ -514,4 +574,4 @@ private fun mockNodeConfiguration(): NodeConfiguration {
useMultiThreadedSMM = false
)).whenever(it).enterpriseConfiguration
}
}
}

View File

@ -21,8 +21,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.node.VersionInfo
import net.corda.node.internal.EnterpriseNode
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.config.*
import net.corda.nodeapi.internal.config.toConfig
import net.corda.nodeapi.internal.network.NetworkParametersCopier
@ -58,7 +57,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
val tempFolder = TemporaryFolder()
private lateinit var defaultNetworkParameters: NetworkParametersCopier
private val startedNodes = mutableListOf<StartedNode<Node>>()
private val startedNodes = mutableListOf<StartedNodeWithInternals>()
private val nodeInfos = mutableListOf<NodeInfo>()
private val portAllocation = PortAllocation.Incremental(10000)
@ -96,9 +95,9 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
@JvmOverloads
fun initNode(legalName: CordaX500Name,
platformVersion: Int = 1,
rpcUsers: List<User> = emptyList(),
configOverrides: Map<String, Any> = emptyMap()): Node {
platformVersion: Int = 1,
rpcUsers: List<User> = emptyList(),
configOverrides: Map<String, Any> = emptyMap()): InProcessNode {
val baseDirectory = baseDirectory(legalName).createDirectories()
val p2pAddress = configOverrides["p2pAddress"] ?: portAllocation.nextHostAndPort().toString()
val config = ConfigHelper.loadConfig(
@ -131,7 +130,6 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
}
defaultNetworkParameters.install(baseDirectory)
return InProcessNode(parsedConfig, MOCK_VERSION_INFO.copy(platformVersion = platformVersion))
}
@ -139,9 +137,9 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
fun startNode(legalName: CordaX500Name,
platformVersion: Int = 1,
rpcUsers: List<User> = emptyList(),
configOverrides: Map<String, Any> = emptyMap()): StartedNode<Node> {
configOverrides: Map<String, Any> = emptyMap()): StartedNodeWithInternals {
val node = initNode(legalName,platformVersion, rpcUsers,configOverrides)
val startedNode = node.start()
val startedNode = node.start() as StartedNodeWithInternals
startedNodes += startedNode
ensureAllNetworkMapCachesHaveAllNodeInfos()
thread(name = legalName.organisation) {