mirror of
https://github.com/corda/corda.git
synced 2025-06-18 07:08:15 +00:00
Removing warnings
This commit is contained in:
7
.idea/compiler.xml
generated
7
.idea/compiler.xml
generated
@ -54,6 +54,12 @@
|
|||||||
<module name="contracts-states_test" target="1.8" />
|
<module name="contracts-states_test" target="1.8" />
|
||||||
<module name="corda-core_integrationTest" target="1.8" />
|
<module name="corda-core_integrationTest" target="1.8" />
|
||||||
<module name="corda-core_smokeTest" target="1.8" />
|
<module name="corda-core_smokeTest" target="1.8" />
|
||||||
|
<module name="corda-enterprise-testing_main" target="1.8" />
|
||||||
|
<module name="corda-enterprise-testing_test" target="1.8" />
|
||||||
|
<module name="corda-enterprise-tools_main" target="1.8" />
|
||||||
|
<module name="corda-enterprise-tools_test" target="1.8" />
|
||||||
|
<module name="corda-enterprise_main" target="1.8" />
|
||||||
|
<module name="corda-enterprise_test" target="1.8" />
|
||||||
<module name="corda-finance_integrationTest" target="1.8" />
|
<module name="corda-finance_integrationTest" target="1.8" />
|
||||||
<module name="corda-project-testing_main" target="1.8" />
|
<module name="corda-project-testing_main" target="1.8" />
|
||||||
<module name="corda-project-testing_test" target="1.8" />
|
<module name="corda-project-testing_test" target="1.8" />
|
||||||
@ -93,6 +99,7 @@
|
|||||||
<module name="demobench_main" target="1.8" />
|
<module name="demobench_main" target="1.8" />
|
||||||
<module name="demobench_test" target="1.8" />
|
<module name="demobench_test" target="1.8" />
|
||||||
<module name="dist_binFiles" target="1.8" />
|
<module name="dist_binFiles" target="1.8" />
|
||||||
|
<module name="dist_installerFiles" target="1.8" />
|
||||||
<module name="dist_licenseFiles" target="1.8" />
|
<module name="dist_licenseFiles" target="1.8" />
|
||||||
<module name="dist_main" target="1.8" />
|
<module name="dist_main" target="1.8" />
|
||||||
<module name="dist_readmeFiles" target="1.8" />
|
<module name="dist_readmeFiles" target="1.8" />
|
||||||
|
@ -7,12 +7,10 @@ import net.corda.core.identity.CordaX500Name
|
|||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.NotaryInfo
|
import net.corda.core.node.NotaryInfo
|
||||||
import net.corda.core.node.services.AttachmentId
|
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.node.services.config.CertChainPolicyConfig
|
|
||||||
import net.corda.node.services.config.EnterpriseConfiguration
|
import net.corda.node.services.config.EnterpriseConfiguration
|
||||||
import net.corda.node.services.config.MutualExclusionConfiguration
|
import net.corda.node.services.config.MutualExclusionConfiguration
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
@ -102,7 +100,7 @@ class BridgeSmokeTest {
|
|||||||
bridgeJar.copyToDirectory(testDir)
|
bridgeJar.copyToDirectory(testDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNetworkParams(baseDirectory: Path) {
|
private fun createNetworkParams(baseDirectory: Path) {
|
||||||
val dummyNotaryParty = TestIdentity(DUMMY_NOTARY_NAME)
|
val dummyNotaryParty = TestIdentity(DUMMY_NOTARY_NAME)
|
||||||
val notaryInfo = NotaryInfo(dummyNotaryParty.party, false)
|
val notaryInfo = NotaryInfo(dummyNotaryParty.party, false)
|
||||||
val copier = NetworkParametersCopier(NetworkParameters(
|
val copier = NetworkParametersCopier(NetworkParameters(
|
||||||
@ -112,18 +110,18 @@ class BridgeSmokeTest {
|
|||||||
maxMessageSize = 10485760,
|
maxMessageSize = 10485760,
|
||||||
maxTransactionSize = 40000,
|
maxTransactionSize = 40000,
|
||||||
epoch = 1,
|
epoch = 1,
|
||||||
whitelistedContractImplementations = emptyMap<String, List<AttachmentId>>()
|
whitelistedContractImplementations = emptyMap()
|
||||||
), overwriteFile = true)
|
), overwriteFile = true)
|
||||||
copier.install(baseDirectory)
|
copier.install(baseDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SSLConfiguration.createBridgeKeyStores(legalName: CordaX500Name,
|
private fun SSLConfiguration.createBridgeKeyStores(legalName: CordaX500Name,
|
||||||
rootCert: X509Certificate = DEV_ROOT_CA.certificate,
|
rootCert: X509Certificate = DEV_ROOT_CA.certificate,
|
||||||
intermediateCa: CertificateAndKeyPair = DEV_INTERMEDIATE_CA) {
|
intermediateCa: CertificateAndKeyPair = DEV_INTERMEDIATE_CA) {
|
||||||
|
|
||||||
certificatesDirectory.createDirectories()
|
certificatesDirectory.createDirectories()
|
||||||
if (!trustStoreFile.exists()) {
|
if (!trustStoreFile.exists()) {
|
||||||
loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/${DEV_CA_TRUST_STORE_FILE}"), DEV_CA_TRUST_STORE_PASS).save(trustStoreFile, trustStorePassword)
|
loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/$DEV_CA_TRUST_STORE_FILE"), DEV_CA_TRUST_STORE_PASS).save(trustStoreFile, trustStorePassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
val (nodeCaCert, nodeCaKeyPair) = createDevNodeCa(intermediateCa, legalName)
|
val (nodeCaCert, nodeCaKeyPair) = createDevNodeCa(intermediateCa, legalName)
|
||||||
@ -189,13 +187,13 @@ class BridgeSmokeTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun serverListening(host: String, port: Int): Boolean {
|
private fun serverListening(host: String, port: Int): Boolean {
|
||||||
var s: Socket? = null
|
var s: Socket? = null
|
||||||
try {
|
return try {
|
||||||
s = Socket(host, port)
|
s = Socket(host, port)
|
||||||
return true
|
true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return false
|
false
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
s?.close()
|
s?.close()
|
||||||
@ -212,7 +210,6 @@ class BridgeSmokeTest {
|
|||||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
doReturn(NetworkHostAndPort("localhost", 11005)).whenever(it).p2pAddress
|
doReturn(NetworkHostAndPort("localhost", 11005)).whenever(it).p2pAddress
|
||||||
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
||||||
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
|
|
||||||
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000), externalBridge = true)).whenever(it).enterpriseConfiguration
|
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000), externalBridge = true)).whenever(it).enterpriseConfiguration
|
||||||
}
|
}
|
||||||
val artemisServer = ArtemisMessagingServer(artemisConfig, NetworkHostAndPort("0.0.0.0", 11005), MAX_MESSAGE_SIZE)
|
val artemisServer = ArtemisMessagingServer(artemisConfig, NetworkHostAndPort("0.0.0.0", 11005), MAX_MESSAGE_SIZE)
|
||||||
|
@ -17,7 +17,6 @@ import net.corda.bridge.createBridgeKeyStores
|
|||||||
import net.corda.bridge.createNetworkParams
|
import net.corda.bridge.createNetworkParams
|
||||||
import net.corda.bridge.services.artemis.BridgeArtemisConnectionServiceImpl
|
import net.corda.bridge.services.artemis.BridgeArtemisConnectionServiceImpl
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.node.services.config.CertChainPolicyConfig
|
|
||||||
import net.corda.node.services.config.EnterpriseConfiguration
|
import net.corda.node.services.config.EnterpriseConfiguration
|
||||||
import net.corda.node.services.config.MutualExclusionConfiguration
|
import net.corda.node.services.config.MutualExclusionConfiguration
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
@ -102,7 +101,6 @@ class ArtemisConnectionTest {
|
|||||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
doReturn(NetworkHostAndPort("localhost", 11005)).whenever(it).p2pAddress
|
doReturn(NetworkHostAndPort("localhost", 11005)).whenever(it).p2pAddress
|
||||||
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
||||||
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
|
|
||||||
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000), externalBridge = true)).whenever(it).enterpriseConfiguration
|
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000), externalBridge = true)).whenever(it).enterpriseConfiguration
|
||||||
}
|
}
|
||||||
val artemisServer = ArtemisMessagingServer(artemisConfig, NetworkHostAndPort("0.0.0.0", 11005), MAX_MESSAGE_SIZE)
|
val artemisServer = ArtemisMessagingServer(artemisConfig, NetworkHostAndPort("0.0.0.0", 11005), MAX_MESSAGE_SIZE)
|
||||||
|
@ -57,14 +57,16 @@ class StateMachineDataModel {
|
|||||||
private val progressTracking by observable(NodeMonitorModel::progressTracking)
|
private val progressTracking by observable(NodeMonitorModel::progressTracking)
|
||||||
private val progressEvents = progressTracking.recordAsAssociation(ProgressTrackingEvent::stateMachineId)
|
private val progressEvents = progressTracking.recordAsAssociation(ProgressTrackingEvent::stateMachineId)
|
||||||
|
|
||||||
val counter = Counter()
|
private val counter = Counter()
|
||||||
|
|
||||||
private val stateMachineIndexMap = HashMap<StateMachineRunId, Int>()
|
private val stateMachineIndexMap = HashMap<StateMachineRunId, Int>()
|
||||||
private val stateMachineStatus = stateMachineUpdates.fold(FXCollections.observableArrayList<SimpleObjectProperty<StateMachineStatus>>()) { list, update ->
|
private val stateMachineStatus = stateMachineUpdates.fold(FXCollections.observableArrayList<SimpleObjectProperty<StateMachineStatus>>()) { list, update ->
|
||||||
when (update) {
|
when (update) {
|
||||||
is StateMachineUpdate.Added -> {
|
is StateMachineUpdate.Added -> {
|
||||||
counter.addSmm()
|
counter.addSmm()
|
||||||
val flowInitiator= update.stateMachineInfo.initiator
|
// TODO Use invocationContext instead
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val flowInitiator = update.stateMachineInfo.initiator
|
||||||
val added: SimpleObjectProperty<StateMachineStatus> =
|
val added: SimpleObjectProperty<StateMachineStatus> =
|
||||||
SimpleObjectProperty(StateMachineStatus.Added(update.id, update.stateMachineInfo.flowLogicClassName, flowInitiator))
|
SimpleObjectProperty(StateMachineStatus.Added(update.id, update.stateMachineInfo.flowLogicClassName, flowInitiator))
|
||||||
list.add(added)
|
list.add(added)
|
||||||
@ -83,7 +85,7 @@ class StateMachineDataModel {
|
|||||||
private val stateMachineDataList = stateMachineStatus.map {
|
private val stateMachineDataList = stateMachineStatus.map {
|
||||||
val smStatus = it.value as StateMachineStatus.Added
|
val smStatus = it.value as StateMachineStatus.Added
|
||||||
val id = smStatus.id
|
val id = smStatus.id
|
||||||
val progress = SimpleObjectProperty(progressEvents.get(id))
|
val progress = SimpleObjectProperty(progressEvents[id])
|
||||||
StateMachineData(id, smStatus.stateMachineName, smStatus.flowInitiator,
|
StateMachineData(id, smStatus.stateMachineName, smStatus.flowInitiator,
|
||||||
Pair(it, EasyBind.map(progress) { ProgressStatus(it?.message) }))
|
Pair(it, EasyBind.map(progress) { ProgressStatus(it?.message) }))
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ data class StateMachineInfo @JvmOverloads constructor(
|
|||||||
* An object representing information about the initiator of the flow. Note that this field is
|
* An object representing information about the initiator of the flow. Note that this field is
|
||||||
* superceded by the [invocationContext] property, which has more detail.
|
* superceded by the [invocationContext] property, which has more detail.
|
||||||
*/
|
*/
|
||||||
@Deprecated("There is more info available using 'context'") val initiator: FlowInitiator,
|
@Deprecated("There is more info available using 'invocationContext'") val initiator: FlowInitiator,
|
||||||
/** A [DataFeed] of the current progress step as a human readable string, and updates to that string. */
|
/** A [DataFeed] of the current progress step as a human readable string, and updates to that string. */
|
||||||
val progressTrackerStepAndUpdates: DataFeed<String, String>?,
|
val progressTrackerStepAndUpdates: DataFeed<String, String>?,
|
||||||
/** An [InvocationContext] describing why and by whom the flow was started. */
|
/** An [InvocationContext] describing why and by whom the flow was started. */
|
||||||
|
@ -136,7 +136,7 @@ class IntegrationTestingTutorial : IntegrationTest() {
|
|||||||
// move to Bob
|
// move to Bob
|
||||||
parallel(
|
parallel(
|
||||||
(1..numberOfStates).map { i ->
|
(1..numberOfStates).map { i ->
|
||||||
expect(match = { it.moved() == i * 100 }) { update: Vault.Update<Cash.State> ->
|
expect(match = { it.moved() == i * 100 }) { _: Vault.Update<Cash.State> ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@ -154,7 +154,7 @@ class IntegrationTestingTutorial : IntegrationTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Vault.Update<Cash.State>.moved(): Int {
|
private fun Vault.Update<Cash.State>.moved(): Int {
|
||||||
val consumedSum = consumed.sumBy { it.state.data.amount.quantity.toInt() }
|
val consumedSum = consumed.sumBy { it.state.data.amount.quantity.toInt() }
|
||||||
val producedSum = produced.sumBy { it.state.data.amount.quantity.toInt() }
|
val producedSum = produced.sumBy { it.state.data.amount.quantity.toInt() }
|
||||||
return consumedSum - producedSum
|
return consumedSum - producedSum
|
||||||
|
@ -40,6 +40,7 @@ import java.time.Duration;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
@ -134,7 +135,7 @@ public class FlowCookbookJava {
|
|||||||
// We retrieve a notary from the network map.
|
// We retrieve a notary from the network map.
|
||||||
// DOCSTART 01
|
// DOCSTART 01
|
||||||
CordaX500Name notaryName = new CordaX500Name("Notary Service", "London", "GB");
|
CordaX500Name notaryName = new CordaX500Name("Notary Service", "London", "GB");
|
||||||
Party specificNotary = getServiceHub().getNetworkMapCache().getNotary(notaryName);
|
Party specificNotary = Objects.requireNonNull(getServiceHub().getNetworkMapCache().getNotary(notaryName));
|
||||||
// Alternatively, we can pick an arbitrary notary from the notary
|
// Alternatively, we can pick an arbitrary notary from the notary
|
||||||
// list. However, it is always preferable to specify the notary
|
// list. However, it is always preferable to specify the notary
|
||||||
// explicitly, as the notary list might change when new notaries are
|
// explicitly, as the notary list might change when new notaries are
|
||||||
@ -378,7 +379,7 @@ public class FlowCookbookJava {
|
|||||||
// Or we can add the output state as a ``TransactionState``, which already specifies
|
// Or we can add the output state as a ``TransactionState``, which already specifies
|
||||||
// the output's contract and notary.
|
// the output's contract and notary.
|
||||||
// DOCSTART 51
|
// DOCSTART 51
|
||||||
TransactionState txState = new TransactionState(ourOutputState, DummyContract.PROGRAM_ID, specificNotary);
|
TransactionState txState = new TransactionState<>(ourOutputState, DummyContract.PROGRAM_ID, specificNotary);
|
||||||
// DOCEND 51
|
// DOCEND 51
|
||||||
|
|
||||||
// Commands can be added as ``Command``s.
|
// Commands can be added as ``Command``s.
|
||||||
@ -662,7 +663,7 @@ public class FlowCookbookJava {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkTransaction(SignedTransaction stx) {
|
protected void checkTransaction(@NotNull SignedTransaction stx) {
|
||||||
requireThat(require -> {
|
requireThat(require -> {
|
||||||
// Any additional checking we see fit...
|
// Any additional checking we see fit...
|
||||||
DummyState outputState = (DummyState) stx.getTx().getOutputs().get(0).getData();
|
DummyState outputState = (DummyState) stx.getTx().getOutputs().get(0).getData();
|
||||||
|
@ -13,6 +13,7 @@ package net.corda.docs.java.tutorial.contract;
|
|||||||
import net.corda.core.contracts.*;
|
import net.corda.core.contracts.*;
|
||||||
import net.corda.core.transactions.LedgerTransaction;
|
import net.corda.core.transactions.LedgerTransaction;
|
||||||
import net.corda.core.transactions.LedgerTransaction.InOutGroup;
|
import net.corda.core.transactions.LedgerTransaction.InOutGroup;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Currency;
|
import java.util.Currency;
|
||||||
@ -22,6 +23,7 @@ import static net.corda.core.contracts.ContractsDSL.requireSingleCommand;
|
|||||||
import static net.corda.core.contracts.ContractsDSL.requireThat;
|
import static net.corda.core.contracts.ContractsDSL.requireThat;
|
||||||
import static net.corda.finance.utils.StateSumming.sumCashBy;
|
import static net.corda.finance.utils.StateSumming.sumCashBy;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class CommercialPaper implements Contract {
|
public class CommercialPaper implements Contract {
|
||||||
// DOCSTART 1
|
// DOCSTART 1
|
||||||
public static final String IOU_CONTRACT_ID = "com.example.contract.IOUContract";
|
public static final String IOU_CONTRACT_ID = "com.example.contract.IOUContract";
|
||||||
@ -29,7 +31,7 @@ public class CommercialPaper implements Contract {
|
|||||||
|
|
||||||
// DOCSTART 3
|
// DOCSTART 3
|
||||||
@Override
|
@Override
|
||||||
public void verify(LedgerTransaction tx) {
|
public void verify(@NotNull LedgerTransaction tx) {
|
||||||
List<InOutGroup<State, State>> groups = tx.groupStates(State.class, State::withoutOwner);
|
List<InOutGroup<State, State>> groups = tx.groupStates(State.class, State::withoutOwner);
|
||||||
CommandWithParties<Commands> cmd = requireSingleCommand(tx.getCommands(), Commands.class);
|
CommandWithParties<Commands> cmd = requireSingleCommand(tx.getCommands(), Commands.class);
|
||||||
// DOCEND 3
|
// DOCEND 3
|
||||||
@ -37,7 +39,7 @@ public class CommercialPaper implements Contract {
|
|||||||
// DOCSTART 4
|
// DOCSTART 4
|
||||||
TimeWindow timeWindow = tx.getTimeWindow();
|
TimeWindow timeWindow = tx.getTimeWindow();
|
||||||
|
|
||||||
for (InOutGroup group : groups) {
|
for (InOutGroup<State, State> group : groups) {
|
||||||
List<State> inputs = group.getInputs();
|
List<State> inputs = group.getInputs();
|
||||||
List<State> outputs = group.getOutputs();
|
List<State> outputs = group.getOutputs();
|
||||||
|
|
||||||
@ -57,6 +59,7 @@ public class CommercialPaper implements Contract {
|
|||||||
Amount<Issued<Currency>> received = sumCashBy(tx.getOutputStates(), input.getOwner());
|
Amount<Issued<Currency>> received = sumCashBy(tx.getOutputStates(), input.getOwner());
|
||||||
if (timeWindow == null) throw new IllegalArgumentException("Redemptions must be timestamped");
|
if (timeWindow == null) throw new IllegalArgumentException("Redemptions must be timestamped");
|
||||||
Instant time = timeWindow.getFromTime();
|
Instant time = timeWindow.getFromTime();
|
||||||
|
if (time == null) throw new IllegalArgumentException("Redemptions must have a from time");
|
||||||
requireThat(require -> {
|
requireThat(require -> {
|
||||||
require.using("the paper must have matured", time.isAfter(input.getMaturityDate()));
|
require.using("the paper must have matured", time.isAfter(input.getMaturityDate()));
|
||||||
require.using("the received amount equals the face value", received == input.getFaceValue());
|
require.using("the received amount equals the face value", received == input.getFaceValue());
|
||||||
@ -68,6 +71,7 @@ public class CommercialPaper implements Contract {
|
|||||||
State output = outputs.get(0);
|
State output = outputs.get(0);
|
||||||
if (timeWindow == null) throw new IllegalArgumentException("Issuances must have a time-window");
|
if (timeWindow == null) throw new IllegalArgumentException("Issuances must have a time-window");
|
||||||
Instant time = timeWindow.getUntilTime();
|
Instant time = timeWindow.getUntilTime();
|
||||||
|
if (time == null) throw new IllegalArgumentException("Issuances must have an until time");
|
||||||
requireThat(require -> {
|
requireThat(require -> {
|
||||||
// Don't allow people to issue commercial paper under other entities identities.
|
// Don't allow people to issue commercial paper under other entities identities.
|
||||||
require.using("output states are issued by a command signer", cmd.getSigners().contains(output.getIssuance().getParty().getOwningKey()));
|
require.using("output states are issued by a command signer", cmd.getSigners().contains(output.getIssuance().getParty().getOwningKey()));
|
||||||
|
@ -11,19 +11,19 @@
|
|||||||
package net.corda.behave.network
|
package net.corda.behave.network
|
||||||
|
|
||||||
import net.corda.behave.database.DatabaseType
|
import net.corda.behave.database.DatabaseType
|
||||||
import net.corda.behave.file.*
|
import net.corda.behave.file.LogSource
|
||||||
import net.corda.behave.monitoring.PatternWatch
|
import net.corda.behave.file.currentDirectory
|
||||||
|
import net.corda.behave.file.stagingRoot
|
||||||
|
import net.corda.behave.file.tmpDirectory
|
||||||
import net.corda.behave.node.Distribution
|
import net.corda.behave.node.Distribution
|
||||||
import net.corda.behave.node.Node
|
import net.corda.behave.node.Node
|
||||||
import net.corda.behave.node.configuration.NotaryType
|
import net.corda.behave.node.configuration.NotaryType
|
||||||
import net.corda.behave.process.Command
|
import net.corda.behave.process.Command
|
||||||
import net.corda.behave.process.JarCommand
|
import net.corda.behave.process.JarCommand
|
||||||
import net.corda.core.CordaException
|
import net.corda.core.CordaException
|
||||||
import net.corda.core.CordaRuntimeException
|
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.core.utilities.seconds
|
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -147,116 +147,8 @@ class Network private constructor(
|
|||||||
* using Local signing and "Auto Approval" mode
|
* using Local signing and "Auto Approval" mode
|
||||||
*/
|
*/
|
||||||
private fun bootstrapDoorman() {
|
private fun bootstrapDoorman() {
|
||||||
|
|
||||||
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
|
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
|
||||||
signalFailure("Bootstrapping a Corda Enterprise network using the Doorman is no longer supported; exiting ...")
|
signalFailure("Bootstrapping a Corda Enterprise network using the Doorman is no longer supported; exiting ...")
|
||||||
return
|
|
||||||
|
|
||||||
// WARNING!! Need to use the correct bootstrapper
|
|
||||||
// only if using OS nodes (need to choose the latest version)
|
|
||||||
val r3node = nodes.values
|
|
||||||
.find { it.config.distribution.type == Distribution.Type.CORDA_ENTERPRISE } ?: throw CordaRuntimeException("Missing R3 distribution node")
|
|
||||||
val distribution = r3node.config.distribution
|
|
||||||
|
|
||||||
// Copy over reference configuration files used in bootstrapping
|
|
||||||
val source = doormanConfigDirectory
|
|
||||||
val doormanTargetDirectory = targetDirectory / "doorman"
|
|
||||||
source.toFile().copyRecursively(doormanTargetDirectory.toFile(), true)
|
|
||||||
|
|
||||||
// Use master version of Bootstrapper
|
|
||||||
val doormanJar = Distribution.R3_MASTER.doormanJar
|
|
||||||
log.info("DoormanJar URL: $doormanJar\n")
|
|
||||||
|
|
||||||
// 1. Create key stores for local signer
|
|
||||||
|
|
||||||
// java -jar doorman-<version>.jar --mode ROOT_KEYGEN
|
|
||||||
log.info("Doorman target directory: $doormanTargetDirectory")
|
|
||||||
runCommand(JarCommand(doormanJar,
|
|
||||||
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf", "--mode", "ROOT_KEYGEN", "--trust-store-password", "password"),
|
|
||||||
doormanTargetDirectory, timeout))
|
|
||||||
|
|
||||||
// java -jar doorman-<version>.jar --mode CA_KEYGEN
|
|
||||||
runCommand(JarCommand(doormanJar,
|
|
||||||
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf", "--mode", "CA_KEYGEN"),
|
|
||||||
doormanTargetDirectory, timeout))
|
|
||||||
|
|
||||||
// 2. Start the doorman service for notary registration
|
|
||||||
doormanNMS = JarCommand(doormanJar,
|
|
||||||
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf"),
|
|
||||||
doormanTargetDirectory, timeout)
|
|
||||||
|
|
||||||
val doormanCommand = runCommand(doormanNMS, noWait = true)
|
|
||||||
log.info("Waiting for DoormanNMS to be alive")
|
|
||||||
|
|
||||||
PatternWatch(doormanCommand.output, "Network management web services started on").await(30.seconds)
|
|
||||||
log.info("DoormanNMS up and running")
|
|
||||||
|
|
||||||
// Notary Nodes
|
|
||||||
val notaryNodes = nodes.values.filter { it.config.notary.notaryType != NotaryType.NONE }
|
|
||||||
notaryNodes.forEach { notaryNode ->
|
|
||||||
val notaryTargetDirectory = targetDirectory / notaryNode.config.name
|
|
||||||
log.info("Notary target directory: $notaryTargetDirectory")
|
|
||||||
|
|
||||||
// 3. Create notary node and register with the doorman
|
|
||||||
runCommand(JarCommand(distribution.cordaJar,
|
|
||||||
arrayOf("--initial-registration",
|
|
||||||
"--base-directory", "$notaryTargetDirectory",
|
|
||||||
"--network-root-truststore", "../doorman/certificates/distribute-nodes/network-root-truststore.jks",
|
|
||||||
"--network-root-truststore-password", "password"),
|
|
||||||
notaryTargetDirectory, timeout))
|
|
||||||
|
|
||||||
// 4. Generate node info files for notary nodes
|
|
||||||
runCommand(JarCommand(distribution.cordaJar,
|
|
||||||
arrayOf("--just-generate-node-info",
|
|
||||||
"--base-directory", "$notaryTargetDirectory"),
|
|
||||||
notaryTargetDirectory, timeout))
|
|
||||||
|
|
||||||
// cp (or ln -s) nodeInfo* notary-node-info
|
|
||||||
val nodeInfoFile = notaryTargetDirectory.toFile().listFiles { _, filename -> filename.matches("nodeInfo-.+".toRegex()) }.firstOrNull() ?: throw CordaRuntimeException("Missing notary nodeInfo file")
|
|
||||||
|
|
||||||
Files.copy(nodeInfoFile.toPath(), (notaryTargetDirectory / "notary-node-info"), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)
|
|
||||||
}
|
|
||||||
|
|
||||||
// exit Doorman process
|
|
||||||
doormanCommand.interrupt()
|
|
||||||
doormanCommand.waitFor()
|
|
||||||
|
|
||||||
// 5. Add notary identities to the network parameters
|
|
||||||
|
|
||||||
// 6. Load initial network parameters file for network map service
|
|
||||||
val networkParamsConfig = if (notaryNodes.isEmpty()) "network-parameters-without-notary.conf" else "network-parameters.conf"
|
|
||||||
val updateNetworkParams = JarCommand(doormanJar,
|
|
||||||
arrayOf("--config-file", "$doormanTargetDirectory/node.conf", "--set-network-parameters", "$doormanTargetDirectory/$networkParamsConfig"),
|
|
||||||
doormanTargetDirectory, timeout)
|
|
||||||
runCommand(updateNetworkParams)
|
|
||||||
|
|
||||||
// 7. Start a fully configured Doorman / NMS
|
|
||||||
doormanNMS = JarCommand(doormanJar,
|
|
||||||
arrayOf("--config-file", "$doormanConfigDirectory/node.conf"),
|
|
||||||
doormanTargetDirectory, timeout)
|
|
||||||
|
|
||||||
val doormanNMSCommand = runCommand(doormanNMS, noWait = true)
|
|
||||||
log.info("Waiting for DoormanNMS to be alive")
|
|
||||||
|
|
||||||
PatternWatch(doormanNMSCommand.output, "Network management web services started on").await(30.seconds)
|
|
||||||
log.info("DoormanNMS up and running")
|
|
||||||
|
|
||||||
// 8. Register other participant nodes
|
|
||||||
val partyNodes = nodes.values.filter { it.config.notary.notaryType == NotaryType.NONE }
|
|
||||||
partyNodes.forEach { partyNode ->
|
|
||||||
val partyTargetDirectory = targetDirectory / partyNode.config.name
|
|
||||||
log.info("Party target directory: $partyTargetDirectory")
|
|
||||||
|
|
||||||
// 3. Create notary node and register with the doorman
|
|
||||||
runCommand(JarCommand(distribution.cordaJar,
|
|
||||||
arrayOf("--initial-registration",
|
|
||||||
"--network-root-truststore", "../doorman/certificates/distribute-nodes/network-root-truststore.jks",
|
|
||||||
"--network-root-truststore-password", "password",
|
|
||||||
"--base-directory", "$partyTargetDirectory"),
|
|
||||||
partyTargetDirectory, timeout))
|
|
||||||
}
|
|
||||||
|
|
||||||
isDoormanNMSRunning = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runCommand(command: Command, noWait: Boolean = false): Command {
|
private fun runCommand(command: Command, noWait: Boolean = false): Command {
|
||||||
@ -446,7 +338,7 @@ class Network private constructor(
|
|||||||
val rpcProxyPortNo = node.config.nodeInterface.rpcProxy
|
val rpcProxyPortNo = node.config.nodeInterface.rpcProxy
|
||||||
val pid = Files.lines(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").findFirst().get()
|
val pid = Files.lines(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").findFirst().get()
|
||||||
// TODO: consider generic implementation to support non *nix platforms
|
// TODO: consider generic implementation to support non *nix platforms
|
||||||
Command(listOf("kill", "-9", "$pid")).run()
|
Command(listOf("kill", "-9", pid)).run()
|
||||||
(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").deleteIfExists()
|
(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").deleteIfExists()
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
|
@ -14,7 +14,6 @@ import net.corda.behave.database.DatabaseConnection
|
|||||||
import net.corda.behave.database.DatabaseType
|
import net.corda.behave.database.DatabaseType
|
||||||
import net.corda.behave.file.LogSource
|
import net.corda.behave.file.LogSource
|
||||||
import net.corda.behave.file.currentDirectory
|
import net.corda.behave.file.currentDirectory
|
||||||
import net.corda.behave.file.stagingRoot
|
|
||||||
import net.corda.behave.monitoring.PatternWatch
|
import net.corda.behave.monitoring.PatternWatch
|
||||||
import net.corda.behave.node.configuration.*
|
import net.corda.behave.node.configuration.*
|
||||||
import net.corda.behave.process.JarCommand
|
import net.corda.behave.process.JarCommand
|
||||||
@ -31,8 +30,8 @@ import net.corda.core.internal.div
|
|||||||
import net.corda.core.internal.exists
|
import net.corda.core.internal.exists
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.minutes
|
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
@ -45,7 +44,7 @@ import java.util.concurrent.CountDownLatch
|
|||||||
*/
|
*/
|
||||||
class Node(
|
class Node(
|
||||||
val config: Configuration,
|
val config: Configuration,
|
||||||
val rootDirectory: Path = currentDirectory,
|
private val rootDirectory: Path = currentDirectory,
|
||||||
private val settings: ServiceSettings = ServiceSettings(),
|
private val settings: ServiceSettings = ServiceSettings(),
|
||||||
val rpcProxy: Boolean = false,
|
val rpcProxy: Boolean = false,
|
||||||
val networkType: Distribution.Type
|
val networkType: Distribution.Type
|
||||||
@ -77,18 +76,6 @@ class Node(
|
|||||||
|
|
||||||
private var haveDependenciesStopped = false
|
private var haveDependenciesStopped = false
|
||||||
|
|
||||||
fun describe(): String {
|
|
||||||
val network = config.nodeInterface
|
|
||||||
val database = config.database
|
|
||||||
return """
|
|
||||||
|Node Information: ${config.name}
|
|
||||||
| - P2P: ${network.host}:${network.p2pPort}
|
|
||||||
| - RPC: ${network.host}:${network.rpcPort}
|
|
||||||
| - SSH: ${network.host}:${network.sshPort}
|
|
||||||
| - DB: ${network.host}:${database.port} (${database.type})
|
|
||||||
|""".trimMargin()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun configure() {
|
fun configure() {
|
||||||
if (isConfigured) { return }
|
if (isConfigured) { return }
|
||||||
isConfigured = true
|
isConfigured = true
|
||||||
@ -164,10 +151,6 @@ class Node(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val nodeInfoGenerationOutput: LogSource by lazy {
|
|
||||||
LogSource(logDirectory, "node-info-gen.log")
|
|
||||||
}
|
|
||||||
|
|
||||||
val logOutput: LogSource by lazy {
|
val logOutput: LogSource by lazy {
|
||||||
val hostname = InetAddress.getLocalHost().hostName
|
val hostname = InetAddress.getLocalHost().hostName
|
||||||
LogSource(logDirectory, "node-$hostname.*.log")
|
LogSource(logDirectory, "node-$hostname.*.log")
|
||||||
@ -387,10 +370,11 @@ class Node(
|
|||||||
val name = name ?: error("Node name not set")
|
val name = name ?: error("Node name not set")
|
||||||
val directory = directory ?: error("Runtime directory not set")
|
val directory = directory ?: error("Runtime directory not set")
|
||||||
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
|
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
|
||||||
val compatibilityZoneURL = null
|
val compatibilityZoneURL = if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null) {
|
||||||
if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null)
|
|
||||||
"http://localhost:1300" // TODO: add additional USE_NETWORK_SERVICES_URL to specify location of existing operational environment to use.
|
"http://localhost:1300" // TODO: add additional USE_NETWORK_SERVICES_URL to specify location of existing operational environment to use.
|
||||||
else null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
return Node(
|
return Node(
|
||||||
Configuration(
|
Configuration(
|
||||||
name,
|
name,
|
||||||
|
@ -72,7 +72,7 @@ class ScenarioState {
|
|||||||
|
|
||||||
inline fun <T> withNetwork(action: ScenarioState.() -> T): T {
|
inline fun <T> withNetwork(action: ScenarioState.() -> T): T {
|
||||||
ensureNetworkIsRunning()
|
ensureNetworkIsRunning()
|
||||||
return action()
|
return this.action()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T> withClient(nodeName: String, crossinline action: (CordaRPCOps) -> T): T {
|
inline fun <T> withClient(nodeName: String, crossinline action: (CordaRPCOps) -> T): T {
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
package net.corda.behave.scenarios.helpers
|
package net.corda.behave.scenarios.helpers
|
||||||
|
|
||||||
import net.corda.behave.logging.getLogger
|
|
||||||
import net.corda.behave.scenarios.ScenarioState
|
import net.corda.behave.scenarios.ScenarioState
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
@ -32,12 +31,12 @@ abstract class Substeps(protected val state: ScenarioState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun <T> withClientProxy(nodeName: String, action: ScenarioState.(CordaRPCOps) -> T): T {
|
protected fun <T> withClientProxy(nodeName: String, action: ScenarioState.(CordaRPCOps) -> T): T {
|
||||||
return state.withClientProxy(nodeName, {
|
return state.withClientProxy(nodeName) {
|
||||||
return@withClientProxy try {
|
try {
|
||||||
action(state, it)
|
action(state, it)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
state.error<T>(ex.message ?: "Failed to execute HTTP call")
|
state.error(ex.message ?: "Failed to execute HTTP call")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'kotlin-kapt'
|
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
|
|
||||||
description 'A javaagent to allow hooking into Kryo'
|
description 'A javaagent to allow hooking into Kryo'
|
||||||
|
@ -114,7 +114,6 @@ object FiberMonitor {
|
|||||||
thread {
|
thread {
|
||||||
while (true) {
|
while (true) {
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
this
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ package net.corda.flowhook
|
|||||||
|
|
||||||
import java.lang.instrument.Instrumentation
|
import java.lang.instrument.Instrumentation
|
||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED", "UNUSED_PARAMETER")
|
||||||
class FlowHookAgent {
|
class FlowHookAgent {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@ -22,4 +22,3 @@ class FlowHookAgent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import org.apache.activemq.artemis.core.io.buffer.TimedBuffer
|
|||||||
import java.sql.Connection
|
import java.sql.Connection
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED", "UNUSED_PARAMETER")
|
||||||
object FlowHookContainer {
|
object FlowHookContainer {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -34,7 +34,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'kotlin-kapt'
|
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'net.corda.plugins.cordapp'
|
apply plugin: 'net.corda.plugins.cordapp'
|
||||||
|
|
||||||
|
@ -11,13 +11,11 @@ import java.util.concurrent.Callable
|
|||||||
|
|
||||||
// Responsible for executing test scenario for a single node executing `LinearStateBatchNotariseFlow` and verifying the results
|
// Responsible for executing test scenario for a single node executing `LinearStateBatchNotariseFlow` and verifying the results
|
||||||
class LinearStateScenarioRunner(options: OptionSet) : AbstractScenarioRunner(options), Callable<Boolean> {
|
class LinearStateScenarioRunner(options: OptionSet) : AbstractScenarioRunner(options), Callable<Boolean> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = contextLogger()
|
private val logger = contextLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun call(): Boolean {
|
override fun call(): Boolean {
|
||||||
|
|
||||||
scenarioInitialized()
|
scenarioInitialized()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -42,6 +40,7 @@ class LinearStateScenarioRunner(options: OptionSet) : AbstractScenarioRunner(opt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
private fun verifyResultsAndStatesTally(results: MutableList<LinearStateBatchNotariseFlow.Result>, states: Vault.Page<LinearStateBatchNotariseContract.State>): Boolean {
|
private fun verifyResultsAndStatesTally(results: MutableList<LinearStateBatchNotariseFlow.Result>, states: Vault.Page<LinearStateBatchNotariseContract.State>): Boolean {
|
||||||
// Unfortunately, there is absolutely nothing in `LinearStateBatchNotariseFlow.Result` which can link it to the original transaction
|
// Unfortunately, there is absolutely nothing in `LinearStateBatchNotariseFlow.Result` which can link it to the original transaction
|
||||||
return true
|
return true
|
||||||
|
@ -27,8 +27,8 @@ class CashSelectionOracleImpl : AbstractCashSelection(maxRetries = 16, retrySlee
|
|||||||
private val log = contextLogger()
|
private val log = contextLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isCompatible(metaData: DatabaseMetaData): Boolean {
|
override fun isCompatible(metadata: DatabaseMetaData): Boolean {
|
||||||
return metaData.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
|
return metadata.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "${this::class.qualifiedName} for '$JDBC_DRIVER_NAME'"
|
override fun toString() = "${this::class.qualifiedName} for '$JDBC_DRIVER_NAME'"
|
||||||
|
@ -16,7 +16,6 @@ import net.corda.core.identity.AbstractParty
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.toBase58String
|
|
||||||
import java.sql.Connection
|
import java.sql.Connection
|
||||||
import java.sql.DatabaseMetaData
|
import java.sql.DatabaseMetaData
|
||||||
import java.sql.ResultSet
|
import java.sql.ResultSet
|
||||||
@ -32,8 +31,8 @@ class CashSelectionSQLServerImpl : AbstractCashSelection(maxRetries = 16, retryS
|
|||||||
private val log = contextLogger()
|
private val log = contextLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isCompatible(metaData: DatabaseMetaData): Boolean {
|
override fun isCompatible(metadata: DatabaseMetaData): Boolean {
|
||||||
return metaData.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
|
return metadata.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "${this::class.qualifiedName} for '$JDBC_DRIVER_NAME'"
|
override fun toString() = "${this::class.qualifiedName} for '$JDBC_DRIVER_NAME'"
|
||||||
|
@ -8,7 +8,6 @@ import java.nio.file.Paths
|
|||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
println("Usage: launcher <main-class-name> [args]")
|
println("Usage: launcher <main-class-name> [args]")
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
@ -54,15 +53,14 @@ fun main(args: Array<String>) {
|
|||||||
@Suppress("unchecked")
|
@Suppress("unchecked")
|
||||||
private fun fixBaseDirArg(args: Array<String>, nodeBaseDirFromArgs: Path): Array<String> {
|
private fun fixBaseDirArg(args: Array<String>, nodeBaseDirFromArgs: Path): Array<String> {
|
||||||
val baseDirIdx = args.indexOf("--base-directory")
|
val baseDirIdx = args.indexOf("--base-directory")
|
||||||
if (baseDirIdx != -1){
|
return if (baseDirIdx != -1) {
|
||||||
args[baseDirIdx+1] = nodeBaseDirFromArgs.toString()
|
// Replace the arg that follows, i.e. --base-directory X
|
||||||
return args
|
// TODO This will not work for --base-directory=X
|
||||||
|
args[baseDirIdx + 1] = nodeBaseDirFromArgs.toString()
|
||||||
|
args
|
||||||
|
} else {
|
||||||
|
args + listOf("--base-directory", nodeBaseDirFromArgs.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
val argsWithBaseDir = args.copyOf(args.size + 2)
|
|
||||||
argsWithBaseDir[argsWithBaseDir.lastIndex - 1] = "--base-directory"
|
|
||||||
argsWithBaseDir[argsWithBaseDir.lastIndex] = nodeBaseDirFromArgs.toString()
|
|
||||||
return argsWithBaseDir as Array<String>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupClassLoader(nodeBaseDir: Path): ClassLoader {
|
private fun setupClassLoader(nodeBaseDir: Path): ClassLoader {
|
||||||
|
@ -257,7 +257,7 @@ class MySQLNotaryServiceTests : IntegrationTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotaryNode(): InternalMockNetwork.MockNode {
|
private fun createNotaryNode(): InternalMockNetwork.MockNode {
|
||||||
val dataStoreProperties = makeTestDataSourceProperties(configSupplier = { _, _ -> ConfigFactory.empty() }, fallBackConfigSupplier = ::inMemoryH2DataSourceConfig).apply {
|
val dataStoreProperties = makeInternalTestDataSourceProperties(configSupplier = { ConfigFactory.empty() }).apply {
|
||||||
setProperty("autoCommit", "false")
|
setProperty("autoCommit", "false")
|
||||||
}
|
}
|
||||||
return mockNet.createUnstartedNode(
|
return mockNet.createUnstartedNode(
|
||||||
|
@ -16,6 +16,7 @@ import net.corda.node.utilities.AffinityExecutor
|
|||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||||
import org.hibernate.Session
|
import org.hibernate.Session
|
||||||
|
import org.hibernate.query.NativeQuery
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.sql.SQLTransientConnectionException
|
import java.sql.SQLTransientConnectionException
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
@ -132,7 +133,7 @@ class RunOnceService(private val database: CordaPersistence, private val machine
|
|||||||
|
|
||||||
private fun insertMutualExclusion(session: Session) {
|
private fun insertMutualExclusion(session: Session) {
|
||||||
val query = session.createNativeQuery("INSERT INTO $TABLE VALUES ('X', :machineName, :pid, CURRENT_TIMESTAMP, :version)", MutualExclusion::class.java)
|
val query = session.createNativeQuery("INSERT INTO $TABLE VALUES ('X', :machineName, :pid, CURRENT_TIMESTAMP, :version)", MutualExclusion::class.java)
|
||||||
query.unwrap(org.hibernate.SQLQuery::class.java).addSynchronizedEntityClass(MutualExclusion::class.java)
|
query.unwrap(NativeQuery::class.java).addSynchronizedEntityClass(MutualExclusion::class.java)
|
||||||
query.setParameter("pid", pid)
|
query.setParameter("pid", pid)
|
||||||
query.setParameter("machineName", machineName)
|
query.setParameter("machineName", machineName)
|
||||||
query.setParameter("version", 0)
|
query.setParameter("version", 0)
|
||||||
|
@ -70,7 +70,7 @@ class MultiThreadedStateMachineManager(
|
|||||||
val checkpointStorage: CheckpointStorage,
|
val checkpointStorage: CheckpointStorage,
|
||||||
val executor: ExecutorService,
|
val executor: ExecutorService,
|
||||||
val database: CordaPersistence,
|
val database: CordaPersistence,
|
||||||
val secureRandom: SecureRandom,
|
private val secureRandom: SecureRandom,
|
||||||
private val unfinishedFibers: ReusableLatch = ReusableLatch(),
|
private val unfinishedFibers: ReusableLatch = ReusableLatch(),
|
||||||
private val classloader: ClassLoader = MultiThreadedStateMachineManager::class.java.classLoader
|
private val classloader: ClassLoader = MultiThreadedStateMachineManager::class.java.classLoader
|
||||||
) : StateMachineManager, StateMachineManagerInternal {
|
) : StateMachineManager, StateMachineManagerInternal {
|
||||||
@ -158,7 +158,7 @@ class MultiThreadedStateMachineManager(
|
|||||||
}
|
}
|
||||||
serviceHub.networkMapCache.nodeReady.then {
|
serviceHub.networkMapCache.nodeReady.then {
|
||||||
resumeRestoredFlows(fibers)
|
resumeRestoredFlows(fibers)
|
||||||
flowMessaging.start { receivedMessage, deduplicationHandler ->
|
flowMessaging.start { _, deduplicationHandler ->
|
||||||
lifeCycle.requireState(State.STARTED, StateMachineStoppedException("Flow cannot be started. State machine is stopped.")) {
|
lifeCycle.requireState(State.STARTED, StateMachineStoppedException("Flow cannot be started. State machine is stopped.")) {
|
||||||
deliverExternalEvent(deduplicationHandler.externalCause)
|
deliverExternalEvent(deduplicationHandler.externalCause)
|
||||||
}
|
}
|
||||||
@ -306,10 +306,10 @@ class MultiThreadedStateMachineManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkQuasarJavaAgentPresence() {
|
private fun checkQuasarJavaAgentPresence() {
|
||||||
check(SuspendableHelper.isJavaAgentActive(), {
|
check(SuspendableHelper.isJavaAgentActive()) {
|
||||||
"""Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM.
|
"""Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM.
|
||||||
#See https://docs.corda.net/troubleshooting.html - 'Fiber classes not instrumented' for more details.""".trimMargin("#")
|
#See https://docs.corda.net/troubleshooting.html - 'Fiber classes not instrumented' for more details.""".trimMargin("#")
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decrementLiveFibers() {
|
private fun decrementLiveFibers() {
|
||||||
@ -324,8 +324,7 @@ class MultiThreadedStateMachineManager(
|
|||||||
return checkpointStorage.getAllCheckpoints().map { (id, serializedCheckpoint) ->
|
return checkpointStorage.getAllCheckpoints().map { (id, serializedCheckpoint) ->
|
||||||
// If a flow is added before start() then don't attempt to restore it
|
// If a flow is added before start() then don't attempt to restore it
|
||||||
if (concurrentBox.content.flows.containsKey(id)) return@map null
|
if (concurrentBox.content.flows.containsKey(id)) return@map null
|
||||||
val checkpoint = deserializeCheckpoint(serializedCheckpoint)
|
val checkpoint = deserializeCheckpoint(serializedCheckpoint) ?: return@map null
|
||||||
if (checkpoint == null) return@map null
|
|
||||||
createFlowFromCheckpoint(
|
createFlowFromCheckpoint(
|
||||||
id = id,
|
id = id,
|
||||||
checkpoint = checkpoint,
|
checkpoint = checkpoint,
|
||||||
@ -440,7 +439,7 @@ class MultiThreadedStateMachineManager(
|
|||||||
val flowId = sessionToFlow[recipientId]
|
val flowId = sessionToFlow[recipientId]
|
||||||
if (flowId == null) {
|
if (flowId == null) {
|
||||||
deduplicationHandler.afterDatabaseTransaction()
|
deduplicationHandler.afterDatabaseTransaction()
|
||||||
if (sessionMessage.payload is EndSessionMessage) {
|
if (sessionMessage.payload === EndSessionMessage) {
|
||||||
logger.debug {
|
logger.debug {
|
||||||
"Got ${EndSessionMessage::class.java.simpleName} for " +
|
"Got ${EndSessionMessage::class.java.simpleName} for " +
|
||||||
"unknown session $recipientId, discarding..."
|
"unknown session $recipientId, discarding..."
|
||||||
@ -537,12 +536,6 @@ class MultiThreadedStateMachineManager(
|
|||||||
isStartIdempotent: Boolean
|
isStartIdempotent: Boolean
|
||||||
): CordaFuture<FlowStateMachine<A>> {
|
): CordaFuture<FlowStateMachine<A>> {
|
||||||
val flowId = StateMachineRunId.createRandom()
|
val flowId = StateMachineRunId.createRandom()
|
||||||
val deduplicationSeed = when (flowStart) {
|
|
||||||
FlowStart.Explicit -> flowId.uuid.toString()
|
|
||||||
is FlowStart.Initiated ->
|
|
||||||
"${flowStart.initiatingMessage.initiatorSessionId.toLong}-" +
|
|
||||||
"${flowStart.initiatingMessage.initiationEntropy}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before we construct the state machine state by freezing the FlowLogic we need to make sure that lazy properties
|
// Before we construct the state machine state by freezing the FlowLogic we need to make sure that lazy properties
|
||||||
// have access to the fiber (and thereby the service hub)
|
// have access to the fiber (and thereby the service hub)
|
||||||
@ -553,7 +546,7 @@ class MultiThreadedStateMachineManager(
|
|||||||
val frozenFlowLogic = (flowLogic as FlowLogic<*>).serialize(context = checkpointSerializationContext!!)
|
val frozenFlowLogic = (flowLogic as FlowLogic<*>).serialize(context = checkpointSerializationContext!!)
|
||||||
|
|
||||||
val flowCorDappVersion = FlowStateMachineImpl.createSubFlowVersion(serviceHub.cordappProvider.getCordappForFlow(flowLogic), serviceHub.myInfo.platformVersion)
|
val flowCorDappVersion = FlowStateMachineImpl.createSubFlowVersion(serviceHub.cordappProvider.getCordappForFlow(flowLogic), serviceHub.myInfo.platformVersion)
|
||||||
val initialCheckpoint = Checkpoint.create(invocationContext, flowStart, flowLogic.javaClass, frozenFlowLogic, ourIdentity, deduplicationSeed, flowCorDappVersion).getOrThrow()
|
val initialCheckpoint = Checkpoint.create(invocationContext, flowStart, flowLogic.javaClass, frozenFlowLogic, ourIdentity, flowCorDappVersion).getOrThrow()
|
||||||
val startedFuture = openFuture<Unit>()
|
val startedFuture = openFuture<Unit>()
|
||||||
val initialState = StateMachineState(
|
val initialState = StateMachineState(
|
||||||
checkpoint = initialCheckpoint,
|
checkpoint = initialCheckpoint,
|
||||||
@ -721,7 +714,7 @@ class MultiThreadedStateMachineManager(
|
|||||||
private fun addAndStartFlow(id: StateMachineRunId, flow: Flow) {
|
private fun addAndStartFlow(id: StateMachineRunId, flow: Flow) {
|
||||||
val checkpoint = flow.fiber.snapshot().checkpoint
|
val checkpoint = flow.fiber.snapshot().checkpoint
|
||||||
for (sessionId in getFlowSessionIds(checkpoint)) {
|
for (sessionId in getFlowSessionIds(checkpoint)) {
|
||||||
sessionToFlow.put(sessionId, id)
|
sessionToFlow[sessionId] = id
|
||||||
}
|
}
|
||||||
concurrentBox.concurrent {
|
concurrentBox.concurrent {
|
||||||
val oldFlow = flows.put(id, flow)
|
val oldFlow = flows.put(id, flow)
|
||||||
|
@ -246,7 +246,6 @@ class RunOnceServiceTest {
|
|||||||
assertEquals('X', result.id)
|
assertEquals('X', result.id)
|
||||||
assertEquals("machine1", result.machineName)
|
assertEquals("machine1", result.machineName)
|
||||||
assertEquals("123", result.pid)
|
assertEquals("123", result.pid)
|
||||||
assertTrue(result.timestamp is LocalDateTime)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +255,6 @@ class RunOnceServiceTest {
|
|||||||
assertEquals('X', result.id)
|
assertEquals('X', result.id)
|
||||||
assertEquals("machine2", result.machineName)
|
assertEquals("machine2", result.machineName)
|
||||||
assertEquals("789", result.pid)
|
assertEquals("789", result.pid)
|
||||||
assertTrue(result.timestamp is LocalDateTime)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import net.corda.testing.node.MockServices
|
|||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import java.lang.reflect.Method
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import javax.persistence.*
|
import javax.persistence.*
|
||||||
@ -32,7 +33,6 @@ import java.net.URLClassLoader
|
|||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
class SchemaMigrationTest {
|
class SchemaMigrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -82,7 +82,7 @@ class SchemaMigrationTest {
|
|||||||
|
|
||||||
// check that the file was picked up
|
// check that the file was picked up
|
||||||
val nrOfChangesOnDiscoveredFile = db.dataSource.connection.use {
|
val nrOfChangesOnDiscoveredFile = db.dataSource.connection.use {
|
||||||
it.createStatement().executeQuery("select count(*) from DATABASECHANGELOG where filename ='migration/${fileName}'").use { rs ->
|
it.createStatement().executeQuery("select count(*) from DATABASECHANGELOG where filename ='migration/$fileName'").use { rs ->
|
||||||
rs.next()
|
rs.next()
|
||||||
rs.getInt(1)
|
rs.getInt(1)
|
||||||
}
|
}
|
||||||
@ -102,9 +102,11 @@ class SchemaMigrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//hacky way to add a folder to the classpath
|
//hacky way to add a folder to the classpath
|
||||||
fun addToClassPath(file: Path) = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java).apply {
|
private fun addToClassPath(file: Path): Method {
|
||||||
|
return URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java).apply {
|
||||||
isAccessible = true
|
isAccessible = true
|
||||||
invoke(ClassLoader.getSystemClassLoader(), file.toFile().toURL())
|
invoke(ClassLoader.getSystemClassLoader(), file.toUri().toURL())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DummyTestSchema
|
object DummyTestSchema
|
||||||
@ -116,9 +118,9 @@ class SchemaMigrationTest {
|
|||||||
|
|
||||||
@ElementCollection
|
@ElementCollection
|
||||||
@Column(name = "participants")
|
@Column(name = "participants")
|
||||||
@CollectionTable(name = "dummy_test_states_parts", joinColumns = arrayOf(
|
@CollectionTable(name = "dummy_test_states_parts", joinColumns = [
|
||||||
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
|
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
|
||||||
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
|
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")])
|
||||||
override var participants: MutableSet<AbstractParty>? = null,
|
override var participants: MutableSet<AbstractParty>? = null,
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
|
@ -40,7 +40,6 @@ class LinearStateBatchNotariseContract : Contract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun verify(tx: LedgerTransaction) {
|
override fun verify(tx: LedgerTransaction) {
|
||||||
val command = tx.commands.requireSingleCommand<Commands>()
|
tx.commands.requireSingleCommand<Commands>()
|
||||||
val timeWindow: TimeWindow? = tx.timeWindow
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,27 +230,6 @@ abstract class OnLedgerAsset<T : Any, C : CommandData, S : FungibleAsset<T>> : C
|
|||||||
return Pair(gathered, gatheredAmount)
|
return Pair(gathered, gatheredAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate an transaction exiting fungible assets from the ledger.
|
|
||||||
*
|
|
||||||
* @param tx transaction builder to add states and commands to.
|
|
||||||
* @param amountIssued the amount to be exited, represented as a quantity of issued currency.
|
|
||||||
* @param assetStates the asset states to take funds from. No checks are done about ownership of these states, it is
|
|
||||||
* the responsibility of the caller to check that they do not attempt to exit funds held by others.
|
|
||||||
* @return the public keys which must sign the transaction for it to be valid.
|
|
||||||
*/
|
|
||||||
@Throws(InsufficientBalanceException::class)
|
|
||||||
@JvmStatic
|
|
||||||
@Deprecated("Replaced with generateExit() which takes in a party to pay change to")
|
|
||||||
fun <S : FungibleAsset<T>, T: Any> generateExit(tx: TransactionBuilder, amountIssued: Amount<Issued<T>>,
|
|
||||||
assetStates: List<StateAndRef<S>>,
|
|
||||||
deriveState: (TransactionState<S>, Amount<Issued<T>>, AbstractParty) -> TransactionState<S>,
|
|
||||||
generateMoveCommand: () -> CommandData,
|
|
||||||
generateExitCommand: (Amount<Issued<T>>) -> CommandData): Set<PublicKey> {
|
|
||||||
val owner = assetStates.map { it.state.data.owner }.toSet().firstOrNull() ?: throw InsufficientBalanceException(amountIssued)
|
|
||||||
return generateExit(tx, amountIssued, assetStates, owner, deriveState, generateMoveCommand, generateExitCommand)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an transaction exiting fungible assets from the ledger.
|
* Generate an transaction exiting fungible assets from the ledger.
|
||||||
*
|
*
|
||||||
@ -323,31 +302,6 @@ abstract class OnLedgerAsset<T : Any, C : CommandData, S : FungibleAsset<T>> : C
|
|||||||
|
|
||||||
abstract fun extractCommands(commands: Collection<CommandWithParties<CommandData>>): Collection<CommandWithParties<C>>
|
abstract fun extractCommands(commands: Collection<CommandWithParties<CommandData>>): Collection<CommandWithParties<C>>
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate an transaction exiting assets from the ledger.
|
|
||||||
*
|
|
||||||
* @param tx transaction builder to add states and commands to.
|
|
||||||
* @param amountIssued the amount to be exited, represented as a quantity of issued currency.
|
|
||||||
* @param assetStates the asset states to take funds from. No checks are done about ownership of these states, it is
|
|
||||||
* the responsibility of the caller to check that they do not exit funds held by others.
|
|
||||||
* @param payChangeTo party to pay any change to; this is normally a confidential identity of the calling
|
|
||||||
* party.
|
|
||||||
* @return the public keys which must sign the transaction for it to be valid.
|
|
||||||
*/
|
|
||||||
@Throws(InsufficientBalanceException::class)
|
|
||||||
@Deprecated("Replaced with generateExit() which takes in a party to pay change to")
|
|
||||||
fun generateExit(tx: TransactionBuilder, amountIssued: Amount<Issued<T>>,
|
|
||||||
assetStates: List<StateAndRef<S>>): Set<PublicKey> {
|
|
||||||
return generateExit(
|
|
||||||
tx,
|
|
||||||
amountIssued,
|
|
||||||
assetStates,
|
|
||||||
deriveState = { state, amount, owner -> deriveState(state, amount, owner) },
|
|
||||||
generateMoveCommand = { -> generateMoveCommand() },
|
|
||||||
generateExitCommand = { amount -> generateExitCommand(amount) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an transaction exiting assets from the ledger.
|
* Generate an transaction exiting assets from the ledger.
|
||||||
*
|
*
|
||||||
@ -367,8 +321,8 @@ abstract class OnLedgerAsset<T : Any, C : CommandData, S : FungibleAsset<T>> : C
|
|||||||
assetStates,
|
assetStates,
|
||||||
payChangeTo,
|
payChangeTo,
|
||||||
deriveState = { state, amount, owner -> deriveState(state, amount, owner) },
|
deriveState = { state, amount, owner -> deriveState(state, amount, owner) },
|
||||||
generateMoveCommand = { -> generateMoveCommand() },
|
generateMoveCommand = { generateMoveCommand() },
|
||||||
generateExitCommand = { amount -> generateExitCommand(amount) }
|
generateExitCommand = { generateExitCommand(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,22 +14,18 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.TransactionState
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.StatesNotAvailableException
|
import net.corda.core.node.services.StatesNotAvailableException
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
|
import net.corda.core.internal.uncheckedCast
|
||||||
import java.sql.*
|
import java.sql.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
|
||||||
import kotlin.concurrent.withLock
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pluggable interface to allow for different cash selection provider implementations
|
* Pluggable interface to allow for different cash selection provider implementations
|
||||||
@ -41,17 +37,17 @@ import kotlin.concurrent.withLock
|
|||||||
abstract class AbstractCashSelection(private val maxRetries: Int = 8, private val retrySleep: Int = 100,
|
abstract class AbstractCashSelection(private val maxRetries: Int = 8, private val retrySleep: Int = 100,
|
||||||
private val retryCap: Int = 2000) {
|
private val retryCap: Int = 2000) {
|
||||||
companion object {
|
companion object {
|
||||||
val instance = AtomicReference<AbstractCashSelection>()
|
private val instance = AtomicReference<AbstractCashSelection>()
|
||||||
|
|
||||||
fun getInstance(metadata: () -> java.sql.DatabaseMetaData): AbstractCashSelection {
|
fun getInstance(metadata: () -> java.sql.DatabaseMetaData): AbstractCashSelection {
|
||||||
return instance.get() ?: {
|
return instance.get() ?: {
|
||||||
val _metadata = metadata()
|
val metadataResult = metadata()
|
||||||
val cashSelectionAlgos = ServiceLoader.load(AbstractCashSelection::class.java).toList()
|
val cashSelectionAlgos = ServiceLoader.load(AbstractCashSelection::class.java).toList()
|
||||||
val cashSelectionAlgo = cashSelectionAlgos.firstOrNull { it.isCompatible(_metadata) }
|
val cashSelectionAlgo = cashSelectionAlgos.firstOrNull { it.isCompatible(metadataResult) }
|
||||||
cashSelectionAlgo?.let {
|
cashSelectionAlgo?.let {
|
||||||
instance.set(cashSelectionAlgo)
|
instance.set(cashSelectionAlgo)
|
||||||
cashSelectionAlgo
|
cashSelectionAlgo
|
||||||
} ?: throw ClassNotFoundException("\nUnable to load compatible cash selection algorithm implementation for JDBC driver ($_metadata)." +
|
} ?: throw ClassNotFoundException("\nUnable to load compatible cash selection algorithm implementation for JDBC driver ($metadataResult)." +
|
||||||
"\nPlease specify an implementation in META-INF/services/${AbstractCashSelection::class.java}")
|
"\nPlease specify an implementation in META-INF/services/${AbstractCashSelection::class.java}")
|
||||||
}.invoke()
|
}.invoke()
|
||||||
}
|
}
|
||||||
@ -84,7 +80,7 @@ abstract class AbstractCashSelection(private val maxRetries: Int = 8, private va
|
|||||||
abstract fun executeQuery(connection: Connection, amount: Amount<Currency>, lockId: UUID, notary: Party?,
|
abstract fun executeQuery(connection: Connection, amount: Amount<Currency>, lockId: UUID, notary: Party?,
|
||||||
onlyFromIssuerParties: Set<AbstractParty>, withIssuerRefs: Set<OpaqueBytes>, withResultSet: (ResultSet) -> Boolean): Boolean
|
onlyFromIssuerParties: Set<AbstractParty>, withIssuerRefs: Set<OpaqueBytes>, withResultSet: (ResultSet) -> Boolean): Boolean
|
||||||
|
|
||||||
override abstract fun toString(): String
|
abstract override fun toString(): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query to gather Cash states that are available and retry if they are temporarily unavailable.
|
* Query to gather Cash states that are available and retry if they are temporarily unavailable.
|
||||||
@ -149,7 +145,7 @@ abstract class AbstractCashSelection(private val maxRetries: Int = 8, private va
|
|||||||
|
|
||||||
if (stateRefs.isNotEmpty()) {
|
if (stateRefs.isNotEmpty()) {
|
||||||
// TODO: future implementation to retrieve contract states from a Vault BLOB store
|
// TODO: future implementation to retrieve contract states from a Vault BLOB store
|
||||||
stateAndRefs.addAll(services.loadStates(stateRefs) as Collection<StateAndRef<Cash.State>>)
|
stateAndRefs.addAll(uncheckedCast(services.loadStates(stateRefs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
val success = stateAndRefs.isNotEmpty() && totalPennies >= amount.quantity
|
val success = stateAndRefs.isNotEmpty() && totalPennies >= amount.quantity
|
||||||
|
@ -13,6 +13,9 @@ package com.r3.corda.enterprise.perftestcordapp.flows
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.cash.selection.AbstractCashSelection
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.cash.selection.AbstractCashSelection
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
|
||||||
import com.r3.corda.enterprise.perftestcordapp.issuedBy
|
import com.r3.corda.enterprise.perftestcordapp.issuedBy
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.InsufficientBalanceException
|
import net.corda.core.contracts.InsufficientBalanceException
|
||||||
@ -60,10 +63,13 @@ class CashExitFlow(private val amount: Amount<Currency>,
|
|||||||
.getInstance { serviceHub.jdbcSession().metaData }
|
.getInstance { serviceHub.jdbcSession().metaData }
|
||||||
.unconsumedCashStatesForSpending(serviceHub, amount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
|
.unconsumedCashStatesForSpending(serviceHub, amount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
|
||||||
val signers = try {
|
val signers = try {
|
||||||
|
val changeOwner = exitStates.map { it.state.data.owner }.toSet().firstOrNull() ?: throw InsufficientBalanceException(amount)
|
||||||
Cash().generateExit(
|
Cash().generateExit(
|
||||||
builder,
|
builder,
|
||||||
amount.issuedBy(issuer),
|
amount.issuedBy(issuer),
|
||||||
exitStates)
|
exitStates,
|
||||||
|
changeOwner
|
||||||
|
)
|
||||||
} catch (e: InsufficientBalanceException) {
|
} catch (e: InsufficientBalanceException) {
|
||||||
throw CashException("Exiting more cash than exists", e)
|
throw CashException("Exiting more cash than exists", e)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
|
||||||
import net.corda.confidential.SwapIdentitiesFlow
|
import net.corda.confidential.SwapIdentitiesFlow
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
@ -23,6 +27,7 @@ import net.corda.core.flows.StartableByRPC
|
|||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.uncheckedCast
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
@ -54,7 +59,7 @@ class CashIssueAndDoublePayment(val amount: Amount<Currency>,
|
|||||||
= txState.copy(data = txState.data.copy(amount = amt, owner = owner))
|
= txState.copy(data = txState.data.copy(amount = amt, owner = owner))
|
||||||
|
|
||||||
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
|
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
|
||||||
val cashStateAndRef = serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single() as StateAndRef<Cash.State>
|
val cashStateAndRef: StateAndRef<Cash.State> = uncheckedCast(serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single())
|
||||||
|
|
||||||
progressTracker.currentStep = GENERATING_ID
|
progressTracker.currentStep = GENERATING_ID
|
||||||
val txIdentities = if (anonymous) {
|
val txIdentities = if (anonymous) {
|
||||||
@ -86,7 +91,7 @@ class CashIssueAndDoublePayment(val amount: Amount<Currency>,
|
|||||||
progressTracker.currentStep = FINALISING_TX
|
progressTracker.currentStep = FINALISING_TX
|
||||||
val notarised1 = finaliseTx(tx1, setOf(recipient), "Unable to notarise spend first time")
|
val notarised1 = finaliseTx(tx1, setOf(recipient), "Unable to notarise spend first time")
|
||||||
try {
|
try {
|
||||||
val notarised2 = finaliseTx(tx2, setOf(recipient), "Unable to notarise spend second time")
|
finaliseTx(tx2, setOf(recipient), "Unable to notarise spend second time")
|
||||||
} catch (expected: CashException) {
|
} catch (expected: CashException) {
|
||||||
val cause = expected.cause
|
val cause = expected.cause
|
||||||
if (cause is NotaryException) {
|
if (cause is NotaryException) {
|
||||||
|
@ -14,12 +14,17 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
|
||||||
import net.corda.confidential.SwapIdentitiesFlow
|
import net.corda.confidential.SwapIdentitiesFlow
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.uncheckedCast
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
@ -51,7 +56,7 @@ class CashIssueAndDuplicatePayment(val amount: Amount<Currency>,
|
|||||||
= txState.copy(data = txState.data.copy(amount = amt, owner = owner))
|
= txState.copy(data = txState.data.copy(amount = amt, owner = owner))
|
||||||
|
|
||||||
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
|
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
|
||||||
val cashStateAndRef = serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single() as StateAndRef<Cash.State>
|
val cashStateAndRef: StateAndRef<Cash.State> = uncheckedCast(serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single())
|
||||||
|
|
||||||
progressTracker.currentStep = GENERATING_ID
|
progressTracker.currentStep = GENERATING_ID
|
||||||
val txIdentities = if (anonymous) {
|
val txIdentities = if (anonymous) {
|
||||||
@ -74,7 +79,7 @@ class CashIssueAndDuplicatePayment(val amount: Amount<Currency>,
|
|||||||
val tx = serviceHub.signInitialTransaction(spendTx, keysForSigning)
|
val tx = serviceHub.signInitialTransaction(spendTx, keysForSigning)
|
||||||
|
|
||||||
progressTracker.currentStep = FINALISING_TX
|
progressTracker.currentStep = FINALISING_TX
|
||||||
val notarised1 = finaliseTx(tx, setOf(recipient), "Unable to notarise spend first time")
|
finaliseTx(tx, setOf(recipient), "Unable to notarise spend first time")
|
||||||
val notarised2 = finaliseTx(tx, setOf(recipient), "Unable to notarise spend second time")
|
val notarised2 = finaliseTx(tx, setOf(recipient), "Unable to notarise spend second time")
|
||||||
|
|
||||||
return Result(notarised2.id, recipient)
|
return Result(notarised2.id, recipient)
|
||||||
|
@ -14,12 +14,17 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
|
||||||
import net.corda.confidential.SwapIdentitiesFlow
|
import net.corda.confidential.SwapIdentitiesFlow
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.internal.uncheckedCast
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.OpaqueBytes
|
import net.corda.core.utilities.OpaqueBytes
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
@ -51,7 +56,7 @@ class CashIssueAndPaymentNoSelection(val amount: Amount<Currency>,
|
|||||||
|
|
||||||
progressTracker.currentStep = GENERATING_TX
|
progressTracker.currentStep = GENERATING_TX
|
||||||
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
|
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
|
||||||
val cashStateAndRef = serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single() as StateAndRef<Cash.State>
|
val cashStateAndRef: StateAndRef<Cash.State> = uncheckedCast(serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single())
|
||||||
|
|
||||||
progressTracker.currentStep = GENERATING_ID
|
progressTracker.currentStep = GENERATING_ID
|
||||||
val txIdentities = if (anonymous) {
|
val txIdentities = if (anonymous) {
|
||||||
|
@ -12,6 +12,9 @@ package com.r3.corda.enterprise.perftestcordapp.flows
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
|
||||||
import com.r3.corda.enterprise.perftestcordapp.issuedBy
|
import com.r3.corda.enterprise.perftestcordapp.issuedBy
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
@ -12,6 +12,10 @@ package com.r3.corda.enterprise.perftestcordapp.flows
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
|
||||||
import net.corda.confidential.SwapIdentitiesFlow
|
import net.corda.confidential.SwapIdentitiesFlow
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.InsufficientBalanceException
|
import net.corda.core.contracts.InsufficientBalanceException
|
||||||
|
@ -104,8 +104,7 @@ class LinearStateBatchNotariseFlow(private val notary: Party,
|
|||||||
}
|
}
|
||||||
builder.addCommand(LinearStateBatchNotariseContract.Commands.Evolve(), us.owningKey)
|
builder.addCommand(LinearStateBatchNotariseContract.Commands.Evolve(), us.owningKey)
|
||||||
builder.setTimeWindow(TimeWindow.fromOnly(serviceHub.clock.instant()))
|
builder.setTimeWindow(TimeWindow.fromOnly(serviceHub.clock.instant()))
|
||||||
val tx = serviceHub.signInitialTransaction(builder, us.owningKey)
|
return serviceHub.signInitialTransaction(builder, us.owningKey)
|
||||||
return tx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
@ -117,17 +116,16 @@ class LinearStateBatchNotariseFlow(private val notary: Party,
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
private fun assembleInitialTx(us: Party): SignedTransaction {
|
private fun assembleInitialTx(us: Party): SignedTransaction {
|
||||||
val builder = TransactionBuilder(notary)
|
val builder = TransactionBuilder(notary)
|
||||||
(0 until n).forEach { outputIndex ->
|
(0 until n).forEach {
|
||||||
builder.addOutputState(TransactionState(LinearStateBatchNotariseContract.State(UniqueIdentifier(), us, serviceHub.clock.instant()), LinearStateBatchNotariseContract.CP_PROGRAM_ID, notary))
|
builder.addOutputState(TransactionState(LinearStateBatchNotariseContract.State(UniqueIdentifier(), us, serviceHub.clock.instant()), LinearStateBatchNotariseContract.CP_PROGRAM_ID, notary))
|
||||||
}
|
}
|
||||||
builder.addCommand(LinearStateBatchNotariseContract.Commands.Create(), us.owningKey)
|
builder.addCommand(LinearStateBatchNotariseContract.Commands.Create(), us.owningKey)
|
||||||
builder.setTimeWindow(TimeWindow.fromOnly(serviceHub.clock.instant()))
|
builder.setTimeWindow(TimeWindow.fromOnly(serviceHub.clock.instant()))
|
||||||
val tx = serviceHub.signInitialTransaction(builder, us.owningKey)
|
return serviceHub.signInitialTransaction(builder, us.owningKey)
|
||||||
return tx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
protected fun finaliseTx(tx: SignedTransaction, message: String): SignedTransaction {
|
private fun finaliseTx(tx: SignedTransaction, message: String): SignedTransaction {
|
||||||
try {
|
try {
|
||||||
return subFlow(FinalityFlow(tx))
|
return subFlow(FinalityFlow(tx))
|
||||||
} catch (e: NotaryException) {
|
} catch (e: NotaryException) {
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
package net.corda.testing.node
|
package net.corda.testing.node
|
||||||
|
|
||||||
import com.google.common.collect.MutableClassToInstanceMap
|
import com.google.common.collect.MutableClassToInstanceMap
|
||||||
import com.typesafe.config.Config
|
|
||||||
import com.typesafe.config.ConfigFactory
|
|
||||||
import com.typesafe.config.ConfigParseOptions
|
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.cordapp.CordappProvider
|
import net.corda.core.cordapp.CordappProvider
|
||||||
@ -34,9 +31,6 @@ import net.corda.core.utilities.NetworkHostAndPort
|
|||||||
import net.corda.node.internal.ServicesForResolutionImpl
|
import net.corda.node.internal.ServicesForResolutionImpl
|
||||||
import net.corda.node.internal.configureDatabase
|
import net.corda.node.internal.configureDatabase
|
||||||
import net.corda.node.internal.cordapp.CordappLoader
|
import net.corda.node.internal.cordapp.CordappLoader
|
||||||
import net.corda.node.services.api.SchemaService
|
|
||||||
import net.corda.node.services.api.VaultServiceInternal
|
|
||||||
import net.corda.node.services.api.WritableTransactionStorage
|
|
||||||
import net.corda.node.services.api.*
|
import net.corda.node.services.api.*
|
||||||
import net.corda.node.services.identity.InMemoryIdentityService
|
import net.corda.node.services.identity.InMemoryIdentityService
|
||||||
import net.corda.node.services.schema.HibernateObserver
|
import net.corda.node.services.schema.HibernateObserver
|
||||||
@ -89,7 +83,7 @@ open class MockServices private constructor(
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
||||||
return makeTestDataSourceProperties(nodeName, null, ::databaseProviderDataSourceConfig, ::inMemoryH2DataSourceConfig)
|
return makeInternalTestDataSourceProperties(nodeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,7 +103,7 @@ open class MockServices private constructor(
|
|||||||
networkParameters: NetworkParameters = testNetworkParameters(),
|
networkParameters: NetworkParameters = testNetworkParameters(),
|
||||||
vararg moreKeys: KeyPair): Pair<CordaPersistence, MockServices> {
|
vararg moreKeys: KeyPair): Pair<CordaPersistence, MockServices> {
|
||||||
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
|
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
|
||||||
val dataSourceProps = makeTestDataSourceProperties(initialIdentity.name.organisation, SecureHash.randomSHA256().toString())
|
val dataSourceProps = makeInternalTestDataSourceProperties(initialIdentity.name.organisation, SecureHash.randomSHA256().toString())
|
||||||
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
|
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
|
||||||
val database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(initialIdentity.name.organisation), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService)
|
val database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(initialIdentity.name.organisation), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService)
|
||||||
val mockService = database.transaction {
|
val mockService = database.transaction {
|
||||||
|
@ -383,7 +383,7 @@ open class InternalMockNetwork(private val cordappPackages: List<String>,
|
|||||||
val config = mockNodeConfiguration().also {
|
val config = mockNodeConfiguration().also {
|
||||||
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
|
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
|
||||||
doReturn(parameters.legalName ?: CordaX500Name("Mock Company $id", "London", "GB")).whenever(it).myLegalName
|
doReturn(parameters.legalName ?: CordaX500Name("Mock Company $id", "London", "GB")).whenever(it).myLegalName
|
||||||
doReturn(makeTestDataSourceProperties("node_$id","net_$networkId")).whenever(it).dataSourceProperties
|
doReturn(makeInternalTestDataSourceProperties("node_$id", "net_$networkId")).whenever(it).dataSourceProperties
|
||||||
doReturn(makeTestDatabaseProperties("node_$id")).whenever(it).database
|
doReturn(makeTestDatabaseProperties("node_$id")).whenever(it).database
|
||||||
doReturn(emptyList<SecureHash>()).whenever(it).extraNetworkMapKeys
|
doReturn(emptyList<SecureHash>()).whenever(it).extraNetworkMapKeys
|
||||||
parameters.configOverrides(it)
|
parameters.configOverrides(it)
|
||||||
|
@ -146,16 +146,16 @@ internal interface InternalMockMessagingService : MessagingService {
|
|||||||
* @param nodeName Reflects the "instance" of the in-memory database or database username/schema.
|
* @param nodeName Reflects the "instance" of the in-memory database or database username/schema.
|
||||||
* Defaults to a random string. Passed to [configSupplier] and [fallBackConfigSupplier] methods.
|
* Defaults to a random string. Passed to [configSupplier] and [fallBackConfigSupplier] methods.
|
||||||
* @param nodeNameExtension Provides additional name extension for [configSupplier] and [fallBackConfigSupplier].
|
* @param nodeNameExtension Provides additional name extension for [configSupplier] and [fallBackConfigSupplier].
|
||||||
* @param configSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName] and [nodeNameExtension] parameters.
|
* @param configSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName].
|
||||||
* Defaults to configuration created when 'databaseProvider' system property is set.
|
* Defaults to configuration created when 'databaseProvider' system property is set.
|
||||||
* @param fallBackConfigSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName] and [nodeNameExtension] parameters.
|
* @param fallBackConfigSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName] and [nodeNameExtension] parameters.
|
||||||
* Defaults to configuration of in-memory H2 instance.
|
* Defaults to configuration of in-memory H2 instance.
|
||||||
*/
|
*/
|
||||||
fun makeTestDataSourceProperties(nodeName: String? = SecureHash.randomSHA256().toString(),
|
fun makeInternalTestDataSourceProperties(nodeName: String? = SecureHash.randomSHA256().toString(),
|
||||||
nodeNameExtension: String? = null,
|
nodeNameExtension: String? = null,
|
||||||
configSupplier: (String?, String?) -> Config = ::databaseProviderDataSourceConfig,
|
configSupplier: (String?) -> Config = ::databaseProviderDataSourceConfig,
|
||||||
fallBackConfigSupplier: (String?, String?) -> Config = ::inMemoryH2DataSourceConfig): Properties {
|
fallBackConfigSupplier: (String?, String?) -> Config = ::inMemoryH2DataSourceConfig): Properties {
|
||||||
val config = configSupplier(nodeName, nodeNameExtension)
|
val config = configSupplier(nodeName)
|
||||||
.withFallback(fallBackConfigSupplier(nodeName, nodeNameExtension))
|
.withFallback(fallBackConfigSupplier(nodeName, nodeNameExtension))
|
||||||
.resolve()
|
.resolve()
|
||||||
|
|
||||||
@ -175,8 +175,8 @@ fun makeTestDataSourceProperties(nodeName: String? = SecureHash.randomSHA256().t
|
|||||||
* @param configSupplier Returns [Config] with databaseProperties, invoked with [nodeName] parameter.
|
* @param configSupplier Returns [Config] with databaseProperties, invoked with [nodeName] parameter.
|
||||||
*/
|
*/
|
||||||
fun makeTestDatabaseProperties(nodeName: String? = null,
|
fun makeTestDatabaseProperties(nodeName: String? = null,
|
||||||
configSupplier: (String?, String?) -> Config = ::databaseProviderDataSourceConfig): DatabaseConfig {
|
configSupplier: (String?) -> Config = ::databaseProviderDataSourceConfig): DatabaseConfig {
|
||||||
val config = configSupplier(nodeName, null)
|
val config = configSupplier(nodeName)
|
||||||
val transactionIsolationLevel = if (config.hasPath(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
|
val transactionIsolationLevel = if (config.hasPath(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
|
||||||
TransactionIsolationLevel.valueOf(config.getString(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
|
TransactionIsolationLevel.valueOf(config.getString(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
|
||||||
else TransactionIsolationLevel.READ_COMMITTED
|
else TransactionIsolationLevel.READ_COMMITTED
|
||||||
@ -188,11 +188,9 @@ fun makeTestDatabaseProperties(nodeName: String? = null,
|
|||||||
* Reads database and dataSource configuration from a file denoted by 'databaseProvider' system property,
|
* Reads database and dataSource configuration from a file denoted by 'databaseProvider' system property,
|
||||||
* overwritten by system properties and defaults to H2 in memory db.
|
* overwritten by system properties and defaults to H2 in memory db.
|
||||||
* @param nodeName Reflects the "instance" of the database username/schema, the value will be used to replace ${custom.nodeOrganizationName} placeholder
|
* @param nodeName Reflects the "instance" of the database username/schema, the value will be used to replace ${custom.nodeOrganizationName} placeholder
|
||||||
* @param notUsed Not uses, required for API backward compatibility.
|
|
||||||
* if the placeholder is present in config.
|
* if the placeholder is present in config.
|
||||||
*/
|
*/
|
||||||
fun databaseProviderDataSourceConfig(nodeName: String? = null, notUsed: String? = null): Config {
|
fun databaseProviderDataSourceConfig(nodeName: String? = null): Config {
|
||||||
|
|
||||||
val parseOptions = ConfigParseOptions.defaults()
|
val parseOptions = ConfigParseOptions.defaults()
|
||||||
|
|
||||||
val keys = listOf(DatabaseConstants.DATA_SOURCE_URL, DatabaseConstants.DATA_SOURCE_CLASSNAME,
|
val keys = listOf(DatabaseConstants.DATA_SOURCE_URL, DatabaseConstants.DATA_SOURCE_CLASSNAME,
|
||||||
@ -218,11 +216,11 @@ fun databaseProviderDataSourceConfig(nodeName: String? = null, notUsed: String?
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates data source configuration for in memory H2 as it would be specified in reference.conf 'datasource' snippet.
|
* Creates data source configuration for in memory H2 as it would be specified in reference.conf 'datasource' snippet.
|
||||||
* @param nodeName Reflects the "instance" of the database username/schema
|
* @param providedNodeName Reflects the "instance" of the database username/schema
|
||||||
* @param postfix Additional postix added to database "instance" name to add uniqueness when running integration tests.
|
* @param postfix Additional postix added to database "instance" name to add uniqueness when running integration tests.
|
||||||
*/
|
*/
|
||||||
fun inMemoryH2DataSourceConfig(nodeName: String? = null, postfix: String? = null) : Config {
|
fun inMemoryH2DataSourceConfig(providedNodeName: String? = null, postfix: String? = null) : Config {
|
||||||
val nodeName = nodeName ?: SecureHash.randomSHA256().toString()
|
val nodeName = providedNodeName ?: SecureHash.randomSHA256().toString()
|
||||||
val h2InstanceName = if (postfix != null) nodeName + "_" + postfix else nodeName
|
val h2InstanceName = if (postfix != null) nodeName + "_" + postfix else nodeName
|
||||||
|
|
||||||
return ConfigFactory.parseMap(mapOf(
|
return ConfigFactory.parseMap(mapOf(
|
||||||
|
@ -12,6 +12,7 @@ import net.corda.core.identity.Party
|
|||||||
import net.corda.core.internal.concurrent.doneFuture
|
import net.corda.core.internal.concurrent.doneFuture
|
||||||
import net.corda.core.internal.openHttpConnection
|
import net.corda.core.internal.openHttpConnection
|
||||||
import net.corda.core.internal.responseAs
|
import net.corda.core.internal.responseAs
|
||||||
|
import net.corda.core.internal.uncheckedCast
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.messaging.*
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
@ -29,7 +30,6 @@ import java.time.Instant
|
|||||||
import javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM
|
import javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM
|
||||||
|
|
||||||
class CordaRPCProxyClient(private val targetHostAndPort: NetworkHostAndPort) : CordaRPCOps {
|
class CordaRPCProxyClient(private val targetHostAndPort: NetworkHostAndPort) : CordaRPCOps {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val log = contextLogger()
|
val log = contextLogger()
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ class CordaRPCProxyClient(private val targetHostAndPort: NetworkHostAndPort) : C
|
|||||||
log.info("Corda RPC Proxy client calling: $flowName with values: $argList")
|
log.info("Corda RPC Proxy client calling: $flowName with values: $argList")
|
||||||
val response = doPost<Any>(targetHostAndPort, "start-flow", argList.serialize().bytes)
|
val response = doPost<Any>(targetHostAndPort, "start-flow", argList.serialize().bytes)
|
||||||
val result = doneFuture(response)
|
val result = doneFuture(response)
|
||||||
return FlowHandleImpl(StateMachineRunId.createRandom(), result) as FlowHandle<T>
|
return uncheckedCast(FlowHandleImpl(StateMachineRunId.createRandom(), result))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun nodeInfo(): NodeInfo {
|
override fun nodeInfo(): NodeInfo {
|
||||||
|
@ -25,6 +25,7 @@ import javax.ws.rs.core.MediaType
|
|||||||
import javax.ws.rs.core.Response
|
import javax.ws.rs.core.Response
|
||||||
import javax.ws.rs.core.Response.status
|
import javax.ws.rs.core.Response.status
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
@Path(RPC_PROXY_PATH)
|
@Path(RPC_PROXY_PATH)
|
||||||
class RPCProxyWebService(targetHostAndPort: NetworkHostAndPort) {
|
class RPCProxyWebService(targetHostAndPort: NetworkHostAndPort) {
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ class RPCProxyWebService(targetHostAndPort: NetworkHostAndPort) {
|
|||||||
fun vaultQuery(input: InputStream): Response {
|
fun vaultQuery(input: InputStream): Response {
|
||||||
log.info("vaultQuery")
|
log.info("vaultQuery")
|
||||||
val contractStateType = input.readBytes().deserialize<String>()
|
val contractStateType = input.readBytes().deserialize<String>()
|
||||||
val clazz = Class.forName(contractStateType) as Class<ContractState>
|
val clazz = Class.forName(contractStateType).asSubclass(ContractState::class.java)
|
||||||
return use {
|
return use {
|
||||||
log.info("Calling vaultQuery with: $clazz")
|
log.info("Calling vaultQuery with: $clazz")
|
||||||
it.vaultQuery(clazz)
|
it.vaultQuery(clazz)
|
||||||
@ -125,7 +126,7 @@ class RPCProxyWebService(targetHostAndPort: NetworkHostAndPort) {
|
|||||||
for (i in argsList.indices) {
|
for (i in argsList.indices) {
|
||||||
log.info("$i: ${argsList[i]}")
|
log.info("$i: ${argsList[i]}")
|
||||||
}
|
}
|
||||||
val flowClass = Class.forName(argsList[0] as String) as Class<FlowLogic<*>>
|
val flowClass = Class.forName(argsList[0] as String).asSubclass(FlowLogic::class.java)
|
||||||
val flowArgs = argsList.drop(1).toTypedArray()
|
val flowArgs = argsList.drop(1).toTypedArray()
|
||||||
log.info("Calling flow: $flowClass with arguments: ${flowArgs.asList()}")
|
log.info("Calling flow: $flowClass with arguments: ${flowArgs.asList()}")
|
||||||
rpcClient.startFlowDynamic(flowClass, *flowArgs).returnValue.getOrThrow()
|
rpcClient.startFlowDynamic(flowClass, *flowArgs).returnValue.getOrThrow()
|
||||||
|
@ -176,7 +176,7 @@ private fun handleCommand(options: OptionSet, baseDirectory: Path, configFile: P
|
|||||||
options.has(DRY_RUN) -> {
|
options.has(DRY_RUN) -> {
|
||||||
val writer = getMigrationOutput(baseDirectory, options)
|
val writer = getMigrationOutput(baseDirectory, options)
|
||||||
migrationLogger.info("Exporting the current db migrations ...")
|
migrationLogger.info("Exporting the current db migrations ...")
|
||||||
runMigrationCommand { migration, dataSource ->
|
runMigrationCommand { migration, _ ->
|
||||||
migration.generateMigrationScript(writer)
|
migration.generateMigrationScript(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ private fun runWithDataSource(config: Configuration, baseDirectory: Path, classL
|
|||||||
val jarDirs = config.jarDirs.map { Paths.get(it) }
|
val jarDirs = config.jarDirs.map { Paths.get(it) }
|
||||||
for (jarDir in jarDirs) {
|
for (jarDir in jarDirs) {
|
||||||
if (!jarDir.exists()) {
|
if (!jarDir.exists()) {
|
||||||
errorAndExit("Could not find the configured JDBC driver directory: '${jarDir}'.")
|
errorAndExit("Could not find the configured JDBC driver directory: '$jarDir'.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ private fun runWithDataSource(config: Configuration, baseDirectory: Path, classL
|
|||||||
errorAndExit("""Failed to create datasource.
|
errorAndExit("""Failed to create datasource.
|
||||||
|Please check that the correct JDBC driver is installed in one of the following folders:
|
|Please check that the correct JDBC driver is installed in one of the following folders:
|
||||||
|${(driversFolder + jarDirs).joinToString("\n\t - ", "\t - ")}
|
|${(driversFolder + jarDirs).joinToString("\n\t - ", "\t - ")}
|
||||||
|Caused By ${e}""".trimMargin(), e)
|
|Caused By $e""".trimMargin(), e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ class TransactionViewer : CordaView("Transactions") {
|
|||||||
}
|
}
|
||||||
override fun computeValue(): SecureHash {
|
override fun computeValue(): SecureHash {
|
||||||
return if (hashList.isEmpty()) SecureHash.zeroHash
|
return if (hashList.isEmpty()) SecureHash.zeroHash
|
||||||
else hashList.fold(hashList[0], { one, another -> one.hashConcat(another) })
|
else hashList.fold(hashList[0], SecureHash::hashConcat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
graphicProperty().bind(hashBinding.map { identicon(it, 30.0) })
|
graphicProperty().bind(hashBinding.map { identicon(it, 30.0) })
|
||||||
@ -325,7 +325,7 @@ class TransactionViewer : CordaView("Transactions") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IOUState -> {
|
is IOUState -> {
|
||||||
fun Pane.partyLabel(party: Party) = label(party.nameOrNull().let { PartyNameFormatter.short.format(it) } ?: "Anonymous") {
|
fun Pane.partyLabel(party: Party) = label(party.nameOrNull().let { PartyNameFormatter.short.format(it) }) {
|
||||||
tooltip(party.owningKey.toBase58String())
|
tooltip(party.owningKey.toBase58String())
|
||||||
}
|
}
|
||||||
row {
|
row {
|
||||||
@ -363,8 +363,7 @@ private fun calculateTotalEquiv(myIdentity: Party?,
|
|||||||
outputs: List<ContractState>): AmountDiff<Currency> {
|
outputs: List<ContractState>): AmountDiff<Currency> {
|
||||||
val (reportingCurrency, exchange) = reportingCurrencyExchange
|
val (reportingCurrency, exchange) = reportingCurrencyExchange
|
||||||
fun List<ContractState>.sum(): Long {
|
fun List<ContractState>.sum(): Long {
|
||||||
val cashSum: Long = map { it as? Cash.State }
|
val cashSum: Long = mapNotNull { it as? Cash.State }
|
||||||
.filterNotNull()
|
|
||||||
.filter { it.owner.owningKey.toKnownParty().value == myIdentity }
|
.filter { it.owner.owningKey.toKnownParty().value == myIdentity }
|
||||||
.map { exchange(it.amount.withoutIssuer()).quantity }
|
.map { exchange(it.amount.withoutIssuer()).quantity }
|
||||||
.sum()
|
.sum()
|
||||||
|
@ -16,7 +16,7 @@ import net.corda.core.flows.FlowLogic
|
|||||||
import net.corda.core.internal.LazyPool
|
import net.corda.core.internal.LazyPool
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.contextLogger
|
||||||
import org.apache.jmeter.config.Argument
|
import org.apache.jmeter.config.Argument
|
||||||
import org.apache.jmeter.config.Arguments
|
import org.apache.jmeter.config.Arguments
|
||||||
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient
|
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient
|
||||||
@ -27,7 +27,7 @@ import java.util.*
|
|||||||
/**
|
/**
|
||||||
* Do most of the work for firing flow start requests via RPC at a Corda node.
|
* Do most of the work for firing flow start requests via RPC at a Corda node.
|
||||||
*/
|
*/
|
||||||
abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
|
abstract class BaseFlowSampler : AbstractJavaSamplerClient() {
|
||||||
companion object {
|
companion object {
|
||||||
private data class RPCParams(val address: NetworkHostAndPort, val user: String, val password: String)
|
private data class RPCParams(val address: NetworkHostAndPort, val user: String, val password: String)
|
||||||
private data class RPCClient(val rpcClient: CordaRPCClient, val rpcConnection: CordaRPCConnection, val ops: CordaRPCOps)
|
private data class RPCClient(val rpcClient: CordaRPCClient, val rpcConnection: CordaRPCConnection, val ops: CordaRPCOps)
|
||||||
@ -40,7 +40,7 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
|
|||||||
|
|
||||||
val allArgs = setOf(label, host, port, username, password)
|
val allArgs = setOf(label, host, port, username, password)
|
||||||
|
|
||||||
val log = loggerFor<BaseFlowSampler>()
|
val log = contextLogger()
|
||||||
|
|
||||||
private val rpcClientPools = Collections.synchronizedMap(mutableMapOf<RPCParams, LazyPool<RPCClient>>())
|
private val rpcClientPools = Collections.synchronizedMap(mutableMapOf<RPCParams, LazyPool<RPCClient>>())
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
|
|||||||
private var rpcParams: RPCParams? = null
|
private var rpcParams: RPCParams? = null
|
||||||
private var rpcPool: LazyPool<RPCClient>? = null
|
private var rpcPool: LazyPool<RPCClient>? = null
|
||||||
|
|
||||||
var labelValue: String? = null
|
private var labelValue: String? = null
|
||||||
|
|
||||||
override fun getDefaultParameters(): Arguments {
|
override fun getDefaultParameters(): Arguments {
|
||||||
// Add copies of all args, since they seem to be mutable.
|
// Add copies of all args, since they seem to be mutable.
|
||||||
@ -70,7 +70,7 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
|
|||||||
labelValue = null
|
labelValue = null
|
||||||
}
|
}
|
||||||
rpcPool = rpcClientPools.computeIfAbsent(rpcParams) {
|
rpcPool = rpcClientPools.computeIfAbsent(rpcParams) {
|
||||||
LazyPool<RPCClient> {
|
LazyPool {
|
||||||
val rpcClient = CordaRPCClient(it.address)
|
val rpcClient = CordaRPCClient(it.address)
|
||||||
val rpcConnection = rpcClient.start(it.user, it.password)
|
val rpcConnection = rpcClient.start(it.user, it.password)
|
||||||
val rpcProxy = rpcConnection.proxy
|
val rpcProxy = rpcConnection.proxy
|
||||||
@ -98,14 +98,14 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
|
|||||||
try {
|
try {
|
||||||
val flowResult = handle.returnValue.get()
|
val flowResult = handle.returnValue.get()
|
||||||
result.sampleEnd()
|
result.sampleEnd()
|
||||||
return result.apply {
|
result.apply {
|
||||||
isSuccessful = true
|
isSuccessful = true
|
||||||
additionalFlowResponseProcessing(context, this, flowResult)
|
additionalFlowResponseProcessing(context, this, flowResult)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
result.sampleEnd()
|
result.sampleEnd()
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return result.apply {
|
result.apply {
|
||||||
isSuccessful = false
|
isSuccessful = false
|
||||||
additionalFlowResponseProcessing(context, this, e)
|
additionalFlowResponseProcessing(context, this, e)
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,6 @@ import net.corda.core.messaging.CordaRPCOps
|
|||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.notarytest.service.JDBCLoadTestFlow
|
import net.corda.notarytest.service.JDBCLoadTestFlow
|
||||||
import java.io.File
|
|
||||||
import java.io.PrintWriter
|
|
||||||
import java.time.Instant
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/** The number of test flows to run on each notary node */
|
/** The number of test flows to run on each notary node */
|
||||||
@ -43,7 +40,7 @@ fun main(args: Array<String>) {
|
|||||||
CordaRPCClient(it).start(notaryDemoUser.username, notaryDemoUser.password).use {
|
CordaRPCClient(it).start(notaryDemoUser.username, notaryDemoUser.password).use {
|
||||||
println(it.proxy.nodeInfo())
|
println(it.proxy.nodeInfo())
|
||||||
val totalTime = Stopwatch.createStarted()
|
val totalTime = Stopwatch.createStarted()
|
||||||
val durations = run(it.proxy, 1)
|
run(it.proxy, 1)
|
||||||
totalTime.stop()
|
totalTime.stop()
|
||||||
|
|
||||||
val totalTx = TEST_RUNS * TRANSACTION_COUNT
|
val totalTx = TEST_RUNS * TRANSACTION_COUNT
|
||||||
@ -65,13 +62,3 @@ private fun run(rpc: CordaRPCOps, inputStateCount: Int? = null): List<Long> {
|
|||||||
flowDuration
|
flowDuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun printCSV(node: NetworkHostAndPort, durations: List<Long>, testRuns: Int, batchSize: Int) {
|
|
||||||
val pw = PrintWriter(File("notarytest-${Instant.now()}-${node.host}${node.port}-${testRuns}x$batchSize.csv"))
|
|
||||||
val sb = StringBuilder()
|
|
||||||
sb.append("$testRuns, $batchSize")
|
|
||||||
sb.append('\n')
|
|
||||||
sb.append(durations.joinToString())
|
|
||||||
pw.write(sb.toString())
|
|
||||||
pw.close()
|
|
||||||
}
|
|
Reference in New Issue
Block a user