mirror of
https://github.com/corda/corda.git
synced 2025-02-07 03:29:19 +00:00
Resolved merge conflicts.
This commit is contained in:
commit
37cadbce69
@ -8,6 +8,8 @@ Unreleased
|
||||
==========
|
||||
* Introduced a hierarchy of ``DatabaseMigrationException``s, allowing ``NodeStartup`` to gracefully inform users of problems related to database migrations before exiting with a non-zero code.
|
||||
|
||||
* Removed -xmx VM argument from Explorer's Capsule setup. This helps avoiding out of memory errors.
|
||||
|
||||
* Shell now kills an ongoing flow when CTRL+C is pressed in the terminal.
|
||||
|
||||
* ``ServiceHub`` and ``CordaRPCOps`` can now safely be used from multiple threads without incurring in database transaction problems.
|
||||
|
@ -130,16 +130,20 @@ Merging the changes back into Corda
|
||||
|
||||
1. Create a pull request from your fork to the ``master`` branch of the Corda repo
|
||||
|
||||
2. In the PR comments box, complete the pull-request checklist:
|
||||
2. In the PR comments box:
|
||||
|
||||
* [ ] Have you run the unit, integration and smoke tests as described here? https://docs.corda.net/head/testing.html
|
||||
* [ ] If you added/changed public APIs, did you write/update the JavaDocs?
|
||||
* [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially
|
||||
release notes?
|
||||
* [ ] If you are contributing for the first time, please read the agreement in CONTRIBUTING.md now and add to this
|
||||
Pull Request that you agree to it.
|
||||
* Complete the pull-request checklist:
|
||||
|
||||
3. In the PR comments box, also add a clear description of the purpose for the PR
|
||||
* [ ] Have you run the unit, integration and smoke tests as described here? https://docs.corda.net/head/testing.html
|
||||
* [ ] If you added/changed public APIs, did you write/update the JavaDocs?
|
||||
* [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially
|
||||
release notes?
|
||||
* [ ] If you are contributing for the first time, please read the agreement in CONTRIBUTING.md now and add to this
|
||||
Pull Request that you agree to it.
|
||||
|
||||
* Add a clear description of the purpose of the PR
|
||||
|
||||
* Add the following statement to confirm that your contribution is your own original work: "I hereby certify that my contribution is in accordance with the Developer Certificate of Origin (https://github.com/corda/corda/blob/master/CONTRIBUTING.md#developer-certificate-of-origin)."
|
||||
|
||||
4. Request a review from a member of the Corda platform team via the `#design channel <http://slack.corda.net/>`_
|
||||
|
||||
|
@ -145,6 +145,9 @@ absolute path to the node's base directory.
|
||||
|
||||
:validating: Boolean to determine whether the notary is a validating or non-validating one.
|
||||
|
||||
:serviceLegalName: If the node is part of a distributed cluster, specify the legal name of the cluster. At runtime, Corda
|
||||
checks whether this name matches the name of the certificate of the notary cluster.
|
||||
|
||||
:raft: If part of a distributed Raft cluster specify this config object, with the following settings:
|
||||
|
||||
:nodeAddress: The host and port to which to bind the embedded Raft server. Note that the Raft cluster uses a
|
||||
|
@ -44,6 +44,7 @@ The most important fields regarding network configuration are:
|
||||
* ``rpcAddress``: The address to which Artemis will bind for RPC calls.
|
||||
* ``webAddress``: The address the webserver should bind. Note that the port must be distinct from that of ``p2pAddress``
|
||||
and ``rpcAddress`` if they are on the same machine.
|
||||
* ``notary.serviceLegalName``: The name of the notary service, required to setup distributed notaries with the network-bootstrapper.
|
||||
|
||||
Bootstrapping the network
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.finance.flows
|
||||
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.contracts.TransactionState
|
||||
import net.corda.core.contracts.withoutIssuer
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
@ -52,30 +53,57 @@ class CashSelectionTest : IntegrationTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `cash selection sees states added in the same transaction`() {
|
||||
driver(DriverParameters(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.finance"))) {
|
||||
val node = startNode().getOrThrow() as InProcessImpl
|
||||
val nodeIdentity = node.services.myInfo.singleIdentity()
|
||||
val issuer = nodeIdentity.ref(1)
|
||||
val coin = 1.DOLLARS.issuedBy(issuer)
|
||||
val exitedAmount = 1.DOLLARS
|
||||
val issuance = TransactionBuilder(null as Party?)
|
||||
issuance.addOutputState(TransactionState(Cash.State(coin, nodeIdentity), Cash.PROGRAM_ID, defaultNotaryIdentity))
|
||||
issuance.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
|
||||
|
||||
//insert ans select in the same transaction
|
||||
val exitStates = node.database.transaction {
|
||||
|
||||
val transaction = node.services.signInitialTransaction(issuance, nodeIdentity.owningKey)
|
||||
node.services.recordTransactions(transaction)
|
||||
|
||||
val builder = TransactionBuilder(notary = null)
|
||||
AbstractCashSelection
|
||||
.getInstance { node.services.jdbcSession().metaData }
|
||||
.unconsumedCashStatesForSpending(node.services, exitedAmount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
|
||||
}
|
||||
val returnedCoinsNumber = 1
|
||||
assertThat(exitStates.size).isEqualTo(returnedCoinsNumber)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `dont return extra coins if the selected amount has been reached`() {
|
||||
driver(DriverParameters(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.finance"))) {
|
||||
val node = startNode().getOrThrow() as InProcessImpl
|
||||
val nodeIdentity = node.services.myInfo.singleIdentity()
|
||||
|
||||
//issue $1 coin twice
|
||||
val issuer = nodeIdentity.ref(1)
|
||||
repeat(2, {
|
||||
val coin = 1.DOLLARS.issuedBy(issuer)
|
||||
val issuance = TransactionBuilder(null as Party?)
|
||||
issuance.addOutputState(TransactionState(Cash.State(coin, nodeIdentity), Cash.PROGRAM_ID, defaultNotaryIdentity))
|
||||
issuance.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
|
||||
|
||||
val transaction = node.services.signInitialTransaction(issuance, nodeIdentity.owningKey)
|
||||
node.database.transaction {
|
||||
node.services.recordTransactions(transaction)
|
||||
}
|
||||
})
|
||||
|
||||
val exitedAmount = 1.DOLLARS
|
||||
|
||||
val builder = TransactionBuilder(notary = null)
|
||||
val exitStates = node.database.transaction {
|
||||
//issue $1 coin twice
|
||||
repeat(2, {
|
||||
val coin = 1.DOLLARS.issuedBy(issuer)
|
||||
val issuance = TransactionBuilder(null as Party?)
|
||||
issuance.addOutputState(TransactionState(Cash.State(coin, nodeIdentity), Cash.PROGRAM_ID, defaultNotaryIdentity))
|
||||
issuance.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey)
|
||||
|
||||
val transaction = node.services.signInitialTransaction(issuance, nodeIdentity.owningKey)
|
||||
|
||||
node.services.recordTransactions(transaction)
|
||||
})
|
||||
|
||||
val exitedAmount = 1.DOLLARS
|
||||
val builder = TransactionBuilder(notary = null)
|
||||
AbstractCashSelection
|
||||
.getInstance { node.services.jdbcSession().metaData }
|
||||
.unconsumedCashStatesForSpending(node.services, exitedAmount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
|
||||
@ -105,12 +133,12 @@ class CashSelectionTest : IntegrationTest() {
|
||||
|
||||
val issuedAmount = coins.reduce { sum, element -> sum + element }.withoutIssuer()
|
||||
|
||||
val availableBalance = node.rpc.getCashBalance(issuedAmount.token)
|
||||
val availableBalance = node.rpc.getCashBalance(issuedAmount.token)
|
||||
|
||||
assertThat(availableBalance).isEqualTo(issuedAmount)
|
||||
assertThat(availableBalance).isEqualTo(issuedAmount)
|
||||
|
||||
val exitedAmount = 3.01.DOLLARS
|
||||
node.rpc.startFlow(::CashExitFlow, exitedAmount, OpaqueBytes.of(1)).returnValue.getOrThrow()
|
||||
node.rpc.startFlow(::CashExitFlow, exitedAmount, OpaqueBytes.of(1)).returnValue.getOrThrow()
|
||||
|
||||
val availableBalanceAfterExit = node.rpc.getCashBalance(issuedAmount.token)
|
||||
|
||||
|
@ -123,6 +123,7 @@ class CordaPersistence(
|
||||
fun createSession(): Connection {
|
||||
// We need to set the database for the current [Thread] or [Fiber] here as some tests share threads across databases.
|
||||
_contextDatabase.set(this)
|
||||
currentDBSession().flush()
|
||||
return contextTransaction.connection
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,9 @@ task buildExplorerJAR(type: FatCapsule, dependsOn: project(':tools:explorer').co
|
||||
caplets = ['ExplorerCaplet']
|
||||
|
||||
// JVM configuration:
|
||||
// - Constrain to small heap sizes to ease development on low end devices.
|
||||
// - Switch to the G1 GC which is going to be the default in Java 9 and gives low pause times/string dedup.
|
||||
//
|
||||
// If you change these flags, please also update Driver.kt
|
||||
jvmArgs = ['-Xmx512m', '-XX:+UseG1GC']
|
||||
jvmArgs = ['-XX:+UseG1GC']
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,12 @@ import org.crsh.cli.*;
|
||||
import org.crsh.command.*;
|
||||
import org.crsh.text.*;
|
||||
import org.crsh.text.ui.TableElement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static net.corda.tools.shell.InteractiveShell.runFlowByNameFragment;
|
||||
import static net.corda.tools.shell.InteractiveShell.runStateMachinesView;
|
||||
|
||||
@ -34,12 +37,16 @@ import static net.corda.tools.shell.InteractiveShell.runStateMachinesView;
|
||||
"flow constructors (the right one is picked automatically) are then specified using the same syntax as for the run command."
|
||||
)
|
||||
public class FlowShellCommand extends InteractiveShellCommand {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(FlowShellCommand.class);
|
||||
|
||||
@Command
|
||||
@Usage("Start a (work)flow on the node. This is how you can change the ledger.")
|
||||
public void start(
|
||||
@Usage("The class name of the flow to run, or an unambiguous substring") @Argument String name,
|
||||
@Usage("The data to pass as input") @Argument(unquote = false) List<String> input
|
||||
) {
|
||||
logger.info("Executing command \"flow start {} {}\",", name, input.stream().collect(joining(" ")));
|
||||
startFlow(name, input, out, ops(), ansiProgressRenderer(), objectMapper());
|
||||
}
|
||||
|
||||
@ -47,6 +54,7 @@ public class FlowShellCommand extends InteractiveShellCommand {
|
||||
@Command
|
||||
@Usage("watch information about state machines running on the node with result information")
|
||||
public void watch(InvocationContext<TableElement> context) throws Exception {
|
||||
logger.info("Executing command \"flow watch\".");
|
||||
runStateMachinesView(out, ops());
|
||||
}
|
||||
|
||||
@ -67,6 +75,7 @@ public class FlowShellCommand extends InteractiveShellCommand {
|
||||
@Command
|
||||
@Usage("list flows that user can start")
|
||||
public void list(InvocationContext<String> context) throws Exception {
|
||||
logger.info("Executing command \"flow list\".");
|
||||
for (String name : ops().registeredFlows()) {
|
||||
context.provide(name + System.lineSeparator());
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import org.crsh.cli.Man;
|
||||
import org.crsh.cli.Usage;
|
||||
import org.crsh.command.InvocationContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -27,11 +29,15 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
// Note that this class cannot be converted to Kotlin because CRaSH does not understand InvocationContext<Map<?, ?>> which
|
||||
// is the closest you can get in Kotlin to raw types.
|
||||
|
||||
public class RunShellCommand extends InteractiveShellCommand {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(RunShellCommand.class);
|
||||
|
||||
@Command
|
||||
@Man(
|
||||
"Runs a method from the CordaRPCOps interface, which is the same interface exposed to RPC clients.\n\n" +
|
||||
@ -40,10 +46,8 @@ public class RunShellCommand extends InteractiveShellCommand {
|
||||
"consulting the developer guide at https://docs.corda.net/api/kotlin/corda/net.corda.core.messaging/-corda-r-p-c-ops/index.html"
|
||||
)
|
||||
@Usage("runs a method from the CordaRPCOps interface on the node.")
|
||||
public Object main(
|
||||
InvocationContext<Map> context,
|
||||
@Usage("The command to run") @Argument(unquote = false) List<String> command
|
||||
) {
|
||||
public Object main(InvocationContext<Map> context, @Usage("The command to run") @Argument(unquote = false) List<String> command) {
|
||||
logger.info("Executing command \"run {}\",", command.stream().collect(joining(" ")));
|
||||
StringToMethodCallParser<CordaRPCOps> parser = new StringToMethodCallParser<>(CordaRPCOps.class, objectMapper());
|
||||
|
||||
if (command == null) {
|
||||
|
@ -15,15 +15,24 @@ package net.corda.tools.shell;
|
||||
import net.corda.tools.shell.utlities.ANSIProgressRenderer;
|
||||
import net.corda.tools.shell.utlities.CRaSHANSIProgressRenderer;
|
||||
import org.crsh.cli.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class StartShellCommand extends InteractiveShellCommand {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(StartShellCommand.class);
|
||||
|
||||
@Command
|
||||
@Man("An alias for 'flow start'. Example: \"start Yo target: Some other company\"")
|
||||
public void main(@Usage("The class name of the flow to run, or an unambiguous substring") @Argument String name,
|
||||
@Usage("The data to pass as input") @Argument(unquote = false) List<String> input) {
|
||||
|
||||
logger.info("Executing command \"start {} {}\",", name, input.stream().collect(joining(" ")));
|
||||
ANSIProgressRenderer ansiProgressRenderer = ansiProgressRenderer();
|
||||
FlowShellCommand.startFlow(name, input, out, ops(), ansiProgressRenderer != null ? ansiProgressRenderer : new CRaSHANSIProgressRenderer(out), objectMapper());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user