mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Change CashIssueFlow to always issue to ourselves
Change CashIssueFlow to always issue to ourselves, and require the cash is then moved in a separate payment operation. This more closely models actual operation inside banks, and is a step towards making all move-like operations go through a uniform verification process.
This commit is contained in:
parent
89476904fc
commit
b76d036843
@ -108,14 +108,10 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
||||
|
||||
@Test
|
||||
fun `cash issue works end to end`() {
|
||||
val anonymous = false
|
||||
rpc.startFlow(::CashIssueFlow,
|
||||
Amount(100, USD),
|
||||
aliceNode.legalIdentity,
|
||||
rpc.nodeIdentity().legalIdentity,
|
||||
OpaqueBytes(ByteArray(1, { 1 })),
|
||||
notaryNode.notaryIdentity,
|
||||
anonymous
|
||||
notaryNode.notaryIdentity
|
||||
)
|
||||
|
||||
vaultUpdates.expectEvents(isStrict = false) {
|
||||
@ -137,8 +133,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
||||
@Test
|
||||
fun `cash issue and move`() {
|
||||
val anonymous = false
|
||||
rpc.startFlow(::CashIssueFlow, 100.DOLLARS, aliceNode.legalIdentity, rpc.nodeIdentity().legalIdentity, OpaqueBytes.of(1),
|
||||
notaryNode.notaryIdentity, anonymous).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, bobNode.legalIdentity, anonymous).returnValue.getOrThrow()
|
||||
|
||||
var issueSmId: StateMachineRunId? = null
|
||||
|
@ -71,7 +71,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
|
||||
|
||||
FlowHandle<AbstractCashFlow.Result> flowHandle = rpcProxy.startFlowDynamic(CashIssueFlow.class,
|
||||
DOLLARS(123), OpaqueBytes.of("1".getBytes()),
|
||||
node.info.getLegalIdentity(), node.info.getLegalIdentity());
|
||||
node.info.getLegalIdentity());
|
||||
System.out.println("Started issuing cash, waiting on result");
|
||||
flowHandle.getReturnValue().get();
|
||||
|
||||
|
@ -78,8 +78,7 @@ class CordaRPCClientTest : NodeBasedTest() {
|
||||
println("Creating proxy")
|
||||
println("Starting flow")
|
||||
val flowHandle = connection!!.proxy.startTrackedFlow(::CashIssueFlow,
|
||||
20.DOLLARS, node.info.legalIdentity,
|
||||
node.info.legalIdentity, OpaqueBytes.of(0), node.info.legalIdentity, true
|
||||
20.DOLLARS, OpaqueBytes.of(0), node.info.legalIdentity
|
||||
)
|
||||
println("Started flow, waiting on result")
|
||||
flowHandle.progress.subscribe {
|
||||
@ -114,8 +113,7 @@ class CordaRPCClientTest : NodeBasedTest() {
|
||||
assertTrue(startCash.isEmpty(), "Should not start with any cash")
|
||||
|
||||
val flowHandle = proxy.startFlow(::CashIssueFlow,
|
||||
123.DOLLARS, node.info.legalIdentity,
|
||||
node.info.legalIdentity, OpaqueBytes.of(0), node.info.legalIdentity, true
|
||||
123.DOLLARS, OpaqueBytes.of(0), node.info.legalIdentity
|
||||
)
|
||||
println("Started issuing cash, waiting on result")
|
||||
flowHandle.returnValue.get()
|
||||
@ -141,15 +139,16 @@ class CordaRPCClientTest : NodeBasedTest() {
|
||||
}
|
||||
}
|
||||
val nodeIdentity = node.info.legalIdentity
|
||||
node.services.startFlow(CashIssueFlow(2000.DOLLARS, nodeIdentity, nodeIdentity, OpaqueBytes.of(0), nodeIdentity, true), FlowInitiator.Shell).resultFuture.getOrThrow()
|
||||
node.services.startFlow(CashIssueFlow(2000.DOLLARS, OpaqueBytes.of(0), nodeIdentity), FlowInitiator.Shell).resultFuture.getOrThrow()
|
||||
proxy.startFlow(::CashIssueFlow,
|
||||
123.DOLLARS, nodeIdentity,
|
||||
nodeIdentity, OpaqueBytes.of(0), nodeIdentity,
|
||||
true
|
||||
123.DOLLARS,
|
||||
OpaqueBytes.of(0),
|
||||
nodeIdentity
|
||||
).returnValue.getOrThrow()
|
||||
proxy.startFlowDynamic(CashIssueFlow::class.java,
|
||||
1000.DOLLARS, OpaqueBytes.of(0),
|
||||
nodeIdentity, nodeIdentity).returnValue.getOrThrow()
|
||||
1000.DOLLARS,
|
||||
OpaqueBytes.of(0),
|
||||
nodeIdentity).returnValue.getOrThrow()
|
||||
assertEquals(2, countRpcFlows)
|
||||
assertEquals(1, countShellFlows)
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ public class StandaloneCordaRPCJavaClientTest {
|
||||
|
||||
FlowHandle<AbstractCashFlow.Result> flowHandle = rpcProxy.startFlowDynamic(CashIssueFlow.class,
|
||||
dollars123, OpaqueBytes.of("1".getBytes()),
|
||||
notaryNode.getLegalIdentity(), notaryNode.getLegalIdentity());
|
||||
notaryNode.getLegalIdentity());
|
||||
System.out.println("Started issuing cash, waiting on result");
|
||||
flowHandle.getReturnValue().get();
|
||||
|
||||
|
@ -3,7 +3,6 @@ package net.corda.kotlin.rpc
|
||||
import com.google.common.hash.Hashing
|
||||
import com.google.common.hash.HashingInputStream
|
||||
import net.corda.client.rpc.CordaRPCConnection
|
||||
import net.corda.client.rpc.notUsed
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.contracts.getCashBalance
|
||||
import net.corda.contracts.getCashBalances
|
||||
@ -96,7 +95,7 @@ class StandaloneCordaRPClientTest {
|
||||
|
||||
@Test
|
||||
fun `test starting flow`() {
|
||||
rpcProxy.startFlow(::CashIssueFlow, 127.POUNDS, OpaqueBytes.of(0), notaryNode.legalIdentity, notaryNode.notaryIdentity)
|
||||
rpcProxy.startFlow(::CashIssueFlow, 127.POUNDS, OpaqueBytes.of(0), notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow(timeout)
|
||||
}
|
||||
|
||||
@ -104,7 +103,7 @@ class StandaloneCordaRPClientTest {
|
||||
fun `test starting tracked flow`() {
|
||||
var trackCount = 0
|
||||
val handle = rpcProxy.startTrackedFlow(
|
||||
::CashIssueFlow, 429.DOLLARS, OpaqueBytes.of(0), notaryNode.legalIdentity, notaryNode.notaryIdentity
|
||||
::CashIssueFlow, 429.DOLLARS, OpaqueBytes.of(0), notaryNode.notaryIdentity
|
||||
)
|
||||
handle.progress.subscribe { msg ->
|
||||
log.info("Flow>> $msg")
|
||||
@ -133,7 +132,7 @@ class StandaloneCordaRPClientTest {
|
||||
}
|
||||
|
||||
// Now issue some cash
|
||||
rpcProxy.startFlow(::CashIssueFlow, 513.SWISS_FRANCS, OpaqueBytes.of(0), notaryNode.legalIdentity, notaryNode.notaryIdentity)
|
||||
rpcProxy.startFlow(::CashIssueFlow, 513.SWISS_FRANCS, OpaqueBytes.of(0), notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow(timeout)
|
||||
assertEquals(1, updateCount.get())
|
||||
}
|
||||
@ -150,7 +149,7 @@ class StandaloneCordaRPClientTest {
|
||||
}
|
||||
|
||||
// Now issue some cash
|
||||
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNode.legalIdentity, notaryNode.notaryIdentity)
|
||||
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow(timeout)
|
||||
assertNotEquals(0, updateCount.get())
|
||||
|
||||
@ -164,7 +163,7 @@ class StandaloneCordaRPClientTest {
|
||||
@Test
|
||||
fun `test vault query by`() {
|
||||
// Now issue some cash
|
||||
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNode.legalIdentity, notaryNode.notaryIdentity)
|
||||
rpcProxy.startFlow(::CashIssueFlow, 629.POUNDS, OpaqueBytes.of(0), notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow(timeout)
|
||||
|
||||
val criteria = QueryCriteria.VaultQueryCriteria(status = Vault.StateStatus.ALL)
|
||||
@ -192,10 +191,7 @@ class StandaloneCordaRPClientTest {
|
||||
val startCash = rpcProxy.getCashBalances()
|
||||
assertTrue(startCash.isEmpty(), "Should not start with any cash")
|
||||
|
||||
val flowHandle = rpcProxy.startFlow(::CashIssueFlow,
|
||||
629.DOLLARS, OpaqueBytes.of(0),
|
||||
notaryNode.legalIdentity, notaryNode.legalIdentity
|
||||
)
|
||||
val flowHandle = rpcProxy.startFlow(::CashIssueFlow, 629.DOLLARS, OpaqueBytes.of(0), notaryNode.legalIdentity)
|
||||
println("Started issuing cash, waiting on result")
|
||||
flowHandle.returnValue.get()
|
||||
|
||||
|
@ -175,8 +175,7 @@ class ContractUpgradeFlowTest {
|
||||
@Test
|
||||
fun `upgrade Cash to v2`() {
|
||||
// Create some cash.
|
||||
val anonymous = false
|
||||
val result = a.services.startFlow(CashIssueFlow(Amount(1000, USD), a.info.legalIdentity, a.info.legalIdentity, OpaqueBytes.of(1), notary, anonymous)).resultFuture
|
||||
val result = a.services.startFlow(CashIssueFlow(Amount(1000, USD), OpaqueBytes.of(1), notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
val stx = result.getOrThrow().stx
|
||||
val stateAndRef = stx.tx.outRef<Cash.State>(0)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package net.corda.docs
|
||||
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.core.internal.concurrent.transpose
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultTrackBy
|
||||
@ -10,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.services.startFlowPermission
|
||||
@ -17,13 +16,7 @@ import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.expect
|
||||
import net.corda.testing.expectEvents
|
||||
import net.corda.testing.parallel
|
||||
import net.corda.testing.sequence
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class IntegrationTestingTutorial {
|
||||
@ -32,7 +25,8 @@ class IntegrationTestingTutorial {
|
||||
// START 1
|
||||
driver {
|
||||
val aliceUser = User("aliceUser", "testPassword1", permissions = setOf(
|
||||
startFlowPermission<CashIssueFlow>()
|
||||
startFlowPermission<CashIssueFlow>(),
|
||||
startFlowPermission<CashPaymentFlow>()
|
||||
))
|
||||
val bobUser = User("bobUser", "testPassword2", permissions = setOf(
|
||||
startFlowPermission<CashPaymentFlow>()
|
||||
@ -62,20 +56,21 @@ class IntegrationTestingTutorial {
|
||||
|
||||
// START 4
|
||||
val issueRef = OpaqueBytes.of(0)
|
||||
val futures = Stack<CordaFuture<*>>()
|
||||
(1..10).map { i ->
|
||||
thread {
|
||||
futures.push(aliceProxy.startFlow(::CashIssueFlow,
|
||||
i.DOLLARS,
|
||||
bob.nodeInfo.legalIdentity,
|
||||
alice.nodeInfo.legalIdentity,
|
||||
issueRef,
|
||||
notary.nodeInfo.notaryIdentity,
|
||||
true
|
||||
).returnValue)
|
||||
}
|
||||
}.forEach(Thread::join) // Ensure the stack of futures is populated.
|
||||
futures.forEach { it.getOrThrow() }
|
||||
aliceProxy.startFlow(::CashIssueFlow,
|
||||
i.DOLLARS,
|
||||
issueRef,
|
||||
notary.nodeInfo.notaryIdentity
|
||||
).returnValue
|
||||
}.transpose().getOrThrow()
|
||||
// We wait for all of the issuances to run before we start making payments
|
||||
(1..10).map { i ->
|
||||
aliceProxy.startFlow(::CashPaymentFlow,
|
||||
i.DOLLARS,
|
||||
bob.nodeInfo.legalIdentity,
|
||||
true
|
||||
).returnValue
|
||||
}.transpose().getOrThrow()
|
||||
|
||||
bobVaultUpdates.expectEvents {
|
||||
parallel(
|
||||
|
@ -128,7 +128,7 @@ fun generateTransactions(proxy: CordaRPCOps) {
|
||||
proxy.startFlow(::CashPaymentFlow, Amount(quantity, USD), me)
|
||||
} else {
|
||||
val quantity = Math.abs(random.nextLong() % 1000)
|
||||
proxy.startFlow(::CashIssueFlow, Amount(quantity, USD), me, me, issueRef, notary, true)
|
||||
proxy.startFlow(::CashIssueFlow, Amount(quantity, USD), issueRef, notary)
|
||||
ownedQuantity += quantity
|
||||
}
|
||||
}
|
||||
|
@ -133,8 +133,7 @@ object TopupIssuerFlow {
|
||||
// invoke Cash subflow to issue Asset
|
||||
progressTracker.currentStep = ISSUING
|
||||
val issuer = serviceHub.myInfo.legalIdentity
|
||||
val issueRecipient = serviceHub.myInfo.legalIdentity
|
||||
val issueCashFlow = CashIssueFlow(amount, issueRecipient, issuer, issuerPartyRef, notaryParty, anonymous = false)
|
||||
val issueCashFlow = CashIssueFlow(amount, issuerPartyRef, notaryParty)
|
||||
val issueTx = subFlow(issueCashFlow)
|
||||
// NOTE: issueCashFlow performs a Broadcast (which stores a local copy of the txn to the ledger)
|
||||
// short-circuit when issuing to self
|
||||
|
@ -65,11 +65,8 @@ class CustomVaultQueryTest {
|
||||
private fun issueCashForCurrency(amountToIssue: Amount<Currency>) {
|
||||
// Use NodeA as issuer and create some dollars
|
||||
val flowHandle1 = nodeA.services.startFlow(CashIssueFlow(amountToIssue,
|
||||
nodeA.info.legalIdentity,
|
||||
nodeA.info.legalIdentity,
|
||||
OpaqueBytes.of(0x01),
|
||||
notaryNode.info.notaryIdentity,
|
||||
anonymous = false))
|
||||
notaryNode.info.notaryIdentity))
|
||||
// Wait for the flow to stop and print
|
||||
flowHandle1.resultFuture.getOrThrow()
|
||||
}
|
||||
|
@ -45,22 +45,16 @@ class FxTransactionBuildTutorialTest {
|
||||
fun `Run ForeignExchangeFlow to completion`() {
|
||||
// Use NodeA as issuer and create some dollars
|
||||
val flowHandle1 = nodeA.services.startFlow(CashIssueFlow(DOLLARS(1000),
|
||||
nodeA.info.legalIdentity,
|
||||
nodeA.info.legalIdentity,
|
||||
OpaqueBytes.of(0x01),
|
||||
notaryNode.info.notaryIdentity,
|
||||
false))
|
||||
notaryNode.info.notaryIdentity))
|
||||
// Wait for the flow to stop and print
|
||||
flowHandle1.resultFuture.getOrThrow()
|
||||
printBalances()
|
||||
|
||||
// Using NodeB as Issuer create some pounds.
|
||||
val flowHandle2 = nodeB.services.startFlow(CashIssueFlow(POUNDS(1000),
|
||||
nodeB.info.legalIdentity,
|
||||
nodeB.info.legalIdentity,
|
||||
OpaqueBytes.of(0x01),
|
||||
notaryNode.info.notaryIdentity,
|
||||
false))
|
||||
notaryNode.info.notaryIdentity))
|
||||
// Wait for flow to come to an end and print
|
||||
flowHandle2.resultFuture.getOrThrow()
|
||||
printBalances()
|
||||
|
@ -6,11 +6,13 @@ import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.FlowHandle
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A command to initiate the cash flow with.
|
||||
*/
|
||||
@Deprecated("Please use the flows directly, these will be removed in a later release")
|
||||
sealed class CashFlowCommand {
|
||||
abstract fun startFlow(proxy: CordaRPCOps): FlowHandle<AbstractCashFlow.Result>
|
||||
|
||||
@ -22,7 +24,10 @@ sealed class CashFlowCommand {
|
||||
val recipient: Party,
|
||||
val notary: Party,
|
||||
val anonymous: Boolean) : CashFlowCommand() {
|
||||
override fun startFlow(proxy: CordaRPCOps) = proxy.startFlow(::CashIssueFlow, amount, recipient, proxy.nodeIdentity().legalIdentity, issueRef, notary, anonymous)
|
||||
override fun startFlow(proxy: CordaRPCOps): FlowHandle<AbstractCashFlow.Result> {
|
||||
proxy.startFlow(::CashIssueFlow, amount, issueRef, notary).returnValue.getOrThrow()
|
||||
return proxy.startFlow(::CashPaymentFlow, amount, recipient, anonymous)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,51 +15,37 @@ import net.corda.core.utilities.ProgressTracker
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Initiates a flow that produces cash issuance transaction.
|
||||
* Initiates a flow that self-issues cash (which should then be sent to recipient(s) using a payment transaction).
|
||||
*
|
||||
* We issue cash only to ourselves so that all KYC/AML checks on payments are enforced consistently, rather than risk
|
||||
* checks for issuance and payments differing. Outside of test scenarios it would be extremely unusual to issue cash
|
||||
* and immediately transfer it, so impact of this limitation is considered minimal.
|
||||
*
|
||||
* @param amount the amount of currency to issue.
|
||||
* @param issuerBankPartyRef a reference to put on the issued currency.
|
||||
* @param issueTo the party who should own the currency after it is issued.
|
||||
* @param notary the notary to set on the output states.
|
||||
*/
|
||||
@StartableByRPC
|
||||
class CashIssueFlow(val amount: Amount<Currency>,
|
||||
val issueTo: Party,
|
||||
val issuerBankParty
|
||||
: Party,
|
||||
val issuerBankPartyRef: OpaqueBytes,
|
||||
val notary: Party,
|
||||
val anonymous: Boolean,
|
||||
progressTracker: ProgressTracker) : AbstractCashFlow<AbstractCashFlow.Result>(progressTracker) {
|
||||
constructor(amount: Amount<Currency>,
|
||||
issuerBankPartyRef: OpaqueBytes,
|
||||
issuerBankParty: Party,
|
||||
issueTo: Party,
|
||||
notary: Party) : this(amount, issueTo, issuerBankParty, issuerBankPartyRef, notary, true, tracker())
|
||||
constructor(amount: Amount<Currency>,
|
||||
issueTo: Party,
|
||||
issuerBankParty: Party,
|
||||
issuerBankPartyRef: OpaqueBytes,
|
||||
notary: Party,
|
||||
anonymous: Boolean) : this(amount, issueTo, issuerBankParty, issuerBankPartyRef, notary, anonymous, tracker())
|
||||
notary: Party) : this(amount, issuerBankPartyRef, notary, tracker())
|
||||
|
||||
@Suspendable
|
||||
override fun call(): AbstractCashFlow.Result {
|
||||
progressTracker.currentStep = GENERATING_ID
|
||||
val txIdentities = if (anonymous) {
|
||||
subFlow(TransactionKeyFlow(issueTo))
|
||||
} else {
|
||||
emptyMap<Party, AnonymousParty>()
|
||||
}
|
||||
val anonymousRecipient = txIdentities[issueTo] ?: issueTo
|
||||
val issuerCert = serviceHub.myInfo.legalIdentityAndCert
|
||||
|
||||
progressTracker.currentStep = GENERATING_TX
|
||||
val builder: TransactionBuilder = TransactionBuilder(notary)
|
||||
val issuer = issuerBankParty.ref(issuerBankPartyRef)
|
||||
val signers = Cash().generateIssue(builder, amount.issuedBy(issuer), anonymousRecipient, notary)
|
||||
val issuer = issuerCert.party.ref(issuerBankPartyRef)
|
||||
val signers = Cash().generateIssue(builder, amount.issuedBy(issuer), issuerCert.party, notary)
|
||||
progressTracker.currentStep = SIGNING_TX
|
||||
val tx = serviceHub.signInitialTransaction(builder, signers)
|
||||
progressTracker.currentStep = FINALISING_TX
|
||||
subFlow(FinalityFlow(tx))
|
||||
return Result(tx, anonymousRecipient)
|
||||
return Result(tx, issuerCert.party)
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +33,7 @@ class CashExitFlowTests {
|
||||
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
||||
|
||||
mockNet.runNetwork()
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance,
|
||||
bankOfCorda,
|
||||
bankOfCorda, ref,
|
||||
notary,
|
||||
anonymous = true)).resultFuture
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance, ref, notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
future.getOrThrow()
|
||||
}
|
||||
@ -50,8 +46,7 @@ class CashExitFlowTests {
|
||||
@Test
|
||||
fun `exit some cash`() {
|
||||
val exitAmount = 500.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashExitFlow(exitAmount,
|
||||
ref)).resultFuture
|
||||
val future = bankOfCordaNode.services.startFlow(CashExitFlow(exitAmount, ref)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
val exitTx = future.getOrThrow().stx.tx
|
||||
val expected = (initialBalance - exitAmount).`issued by`(bankOfCorda.ref(ref))
|
||||
@ -64,8 +59,7 @@ class CashExitFlowTests {
|
||||
@Test
|
||||
fun `exit zero cash`() {
|
||||
val expected = 0.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashExitFlow(expected,
|
||||
ref)).resultFuture
|
||||
val future = bankOfCordaNode.services.startFlow(CashExitFlow(expected, ref)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
assertFailsWith<CashException> {
|
||||
future.getOrThrow()
|
||||
|
@ -42,12 +42,7 @@ class CashIssueFlowTests {
|
||||
fun `issue some cash`() {
|
||||
val expected = 500.DOLLARS
|
||||
val ref = OpaqueBytes.of(0x01)
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(expected,
|
||||
bankOfCorda,
|
||||
bankOfCorda,
|
||||
ref,
|
||||
notary,
|
||||
anonymous = true)).resultFuture
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(expected, ref, notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
val issueTx = future.getOrThrow().stx
|
||||
val output = issueTx.tx.outputsOfType<Cash.State>().single()
|
||||
@ -58,12 +53,7 @@ class CashIssueFlowTests {
|
||||
fun `issue zero cash`() {
|
||||
val expected = 0.DOLLARS
|
||||
val ref = OpaqueBytes.of(0x01)
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(expected,
|
||||
bankOfCorda,
|
||||
bankOfCorda,
|
||||
ref,
|
||||
notary,
|
||||
anonymous = true)).resultFuture
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(expected, ref, notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
future.getOrThrow()
|
||||
|
@ -37,12 +37,7 @@ class CashPaymentFlowTests {
|
||||
notary = notaryNode.info.notaryIdentity
|
||||
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
||||
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance,
|
||||
bankOfCorda,
|
||||
bankOfCorda,
|
||||
ref,
|
||||
notary,
|
||||
true)).resultFuture
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance, ref, notary)).resultFuture
|
||||
mockNet.runNetwork()
|
||||
future.getOrThrow()
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class NodePerformanceTests {
|
||||
a.rpcClientToNode().use("A", "A") { connection ->
|
||||
println("ISSUING")
|
||||
val doneFutures = (1..100).toList().parallelStream().map {
|
||||
connection.proxy.startFlow(::CashIssueFlow, 1.DOLLARS, OpaqueBytes.of(0), a.nodeInfo.legalIdentity, a.nodeInfo.notaryIdentity).returnValue
|
||||
connection.proxy.startFlow(::CashIssueFlow, 1.DOLLARS, OpaqueBytes.of(0), a.nodeInfo.notaryIdentity).returnValue
|
||||
}.toList()
|
||||
doneFutures.transpose().get()
|
||||
println("STARTING PAYMENT")
|
||||
|
@ -134,14 +134,10 @@ class DistributedServiceTests : DriverBasedTest() {
|
||||
}
|
||||
|
||||
private fun issueCash(amount: Amount<Currency>) {
|
||||
val issueHandle = aliceProxy.startFlow(
|
||||
::CashIssueFlow,
|
||||
amount, OpaqueBytes.of(0), alice.nodeInfo.legalIdentity, raftNotaryIdentity)
|
||||
issueHandle.returnValue.getOrThrow()
|
||||
aliceProxy.startFlow(::CashIssueFlow, amount, OpaqueBytes.of(0), raftNotaryIdentity).returnValue.getOrThrow()
|
||||
}
|
||||
|
||||
private fun paySelf(amount: Amount<Currency>) {
|
||||
val payHandle = aliceProxy.startFlow(::CashPaymentFlow, amount, alice.nodeInfo.legalIdentity)
|
||||
payHandle.returnValue.getOrThrow()
|
||||
aliceProxy.startFlow(::CashPaymentFlow, amount, alice.nodeInfo.legalIdentity).returnValue.getOrThrow()
|
||||
}
|
||||
}
|
||||
|
@ -93,9 +93,8 @@ class CordaRPCOpsImplTest {
|
||||
}
|
||||
|
||||
// Tell the monitoring service node to issue some cash
|
||||
val anonymous = false
|
||||
val recipient = aliceNode.info.legalIdentity
|
||||
val result = rpc.startFlow(::CashIssueFlow, Amount(quantity, GBP), recipient, rpc.nodeIdentity().legalIdentity, ref, notaryNode.info.notaryIdentity, anonymous)
|
||||
val result = rpc.startFlow(::CashIssueFlow, Amount(quantity, GBP), ref, notaryNode.info.notaryIdentity)
|
||||
mockNet.runNetwork()
|
||||
|
||||
var issueSmId: StateMachineRunId? = null
|
||||
@ -133,11 +132,8 @@ class CordaRPCOpsImplTest {
|
||||
val anonymous = false
|
||||
val result = rpc.startFlow(::CashIssueFlow,
|
||||
100.DOLLARS,
|
||||
aliceNode.info.legalIdentity,
|
||||
rpc.nodeIdentity().legalIdentity,
|
||||
OpaqueBytes(ByteArray(1, { 1 })),
|
||||
notaryNode.info.notaryIdentity,
|
||||
false
|
||||
notaryNode.info.notaryIdentity
|
||||
)
|
||||
|
||||
mockNet.runNetwork()
|
||||
@ -212,14 +208,7 @@ class CordaRPCOpsImplTest {
|
||||
fun `cash command by user not permissioned for cash`() {
|
||||
CURRENT_RPC_CONTEXT.set(RpcContext(User("user", "pwd", permissions = emptySet())))
|
||||
assertThatExceptionOfType(PermissionException::class.java).isThrownBy {
|
||||
rpc.startFlow(::CashIssueFlow,
|
||||
Amount(100, USD),
|
||||
aliceNode.info.legalIdentity,
|
||||
rpc.nodeIdentity().legalIdentity,
|
||||
OpaqueBytes(ByteArray(1, { 1 })),
|
||||
notaryNode.info.notaryIdentity,
|
||||
false
|
||||
)
|
||||
rpc.startFlow(::CashIssueFlow, Amount(100, USD), OpaqueBytes(ByteArray(1, { 1 })), notaryNode.info.notaryIdentity)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -330,11 +330,8 @@ class FlowFrameworkTests {
|
||||
assertEquals(notary1.info.notaryIdentity, notary2.info.notaryIdentity)
|
||||
node1.services.startFlow(CashIssueFlow(
|
||||
2000.DOLLARS,
|
||||
node1.info.legalIdentity,
|
||||
node1.info.legalIdentity,
|
||||
OpaqueBytes.of(0x01),
|
||||
notary1.info.notaryIdentity,
|
||||
anonymous = false))
|
||||
notary1.info.notaryIdentity))
|
||||
// We pay a couple of times, the notary picking should go round robin
|
||||
for (i in 1..3) {
|
||||
val flow = node1.services.startFlow(CashPaymentFlow(500.DOLLARS, node2.info.legalIdentity, anonymous = false))
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
@ -20,7 +21,9 @@ class BankOfCordaRPCClientTest {
|
||||
@Test
|
||||
fun `issuer flow via RPC`() {
|
||||
driver(dsl = {
|
||||
val bocManager = User("bocManager", "password1", permissions = setOf(startFlowPermission<CashIssueFlow>()))
|
||||
val bocManager = User("bocManager", "password1", permissions = setOf(
|
||||
startFlowPermission<CashIssueFlow>(),
|
||||
startFlowPermission<CashPaymentFlow>()))
|
||||
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet())
|
||||
val (nodeBankOfCorda, nodeBigCorporation) = listOf(
|
||||
startNode(BOC.name, setOf(ServiceInfo(SimpleNotaryService.type)), listOf(bocManager)),
|
||||
@ -47,10 +50,12 @@ class BankOfCordaRPCClientTest {
|
||||
bocProxy.startFlow(
|
||||
::CashIssueFlow,
|
||||
1000.DOLLARS,
|
||||
nodeBigCorporation.nodeInfo.legalIdentity,
|
||||
nodeBankOfCorda.nodeInfo.legalIdentity,
|
||||
BIG_CORP_PARTY_REF,
|
||||
nodeBankOfCorda.nodeInfo.notaryIdentity,
|
||||
nodeBankOfCorda.nodeInfo.notaryIdentity).returnValue.getOrThrow()
|
||||
bocProxy.startFlow(
|
||||
::CashPaymentFlow,
|
||||
1000.DOLLARS,
|
||||
nodeBigCorporation.nodeInfo.legalIdentity,
|
||||
anonymous).returnValue.getOrThrow()
|
||||
|
||||
// Check Bank of Corda Vault Updates
|
||||
|
@ -70,7 +70,9 @@ private class BankOfCordaDriver {
|
||||
startFlowPermission<CashPaymentFlow>(),
|
||||
startFlowPermission<CashIssueFlow>(),
|
||||
startFlowPermission<CashExitFlow>()))
|
||||
val bigCorpUser = User(BIGCORP_USERNAME, "test", permissions = setOf(startFlowPermission<CashPaymentFlow>()))
|
||||
val bigCorpUser = User(BIGCORP_USERNAME, "test",
|
||||
permissions = setOf(
|
||||
startFlowPermission<CashPaymentFlow>()))
|
||||
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||
val bankOfCorda = startNode(
|
||||
BOC.name,
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.testing.http.HttpApi
|
||||
import java.util.*
|
||||
|
||||
@ -28,6 +29,8 @@ class BankOfCordaClientApi(val hostAndPort: NetworkHostAndPort) {
|
||||
|
||||
/**
|
||||
* RPC API
|
||||
*
|
||||
* @return a pair of the issuing and payment transactions.
|
||||
*/
|
||||
fun requestRPCIssue(params: IssueRequestParams): SignedTransaction {
|
||||
val client = CordaRPCClient(hostAndPort)
|
||||
@ -38,8 +41,6 @@ class BankOfCordaClientApi(val hostAndPort: NetworkHostAndPort) {
|
||||
// Resolve parties via RPC
|
||||
val issueToParty = rpc.partyFromX500Name(params.issueToPartyName)
|
||||
?: throw Exception("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
||||
val issuerBankParty = rpc.partyFromX500Name(params.issuerBankName)
|
||||
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
|
||||
val notaryLegalIdentity = rpc.partyFromX500Name(params.notaryName)
|
||||
?: throw IllegalStateException("Unable to locate ${params.notaryName} in Network Map Service")
|
||||
val notaryNode = rpc.nodeIdentityFromParty(notaryLegalIdentity)
|
||||
@ -48,7 +49,9 @@ class BankOfCordaClientApi(val hostAndPort: NetworkHostAndPort) {
|
||||
val amount = Amount(params.amount, Currency.getInstance(params.currency))
|
||||
val issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
||||
|
||||
return rpc.startFlow(::CashIssueFlow, amount, issueToParty, issuerBankParty, issuerBankPartyRef, notaryNode.notaryIdentity, params.anonymous)
|
||||
rpc.startFlow(::CashIssueFlow, amount, issuerBankPartyRef, notaryNode.notaryIdentity)
|
||||
.returnValue.getOrThrow().stx
|
||||
return rpc.startFlow(::CashPaymentFlow, amount, issueToParty, params.anonymous)
|
||||
.returnValue.getOrThrow().stx
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
@ -53,12 +54,13 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
||||
|
||||
val amount = Amount(params.amount, Currency.getInstance(params.currency))
|
||||
val issuerBankPartyRef = OpaqueBytes.of(params.issuerBankPartyRef.toByte())
|
||||
val anonymous = params.anonymous
|
||||
|
||||
// invoke client side of Issuer Flow: IssuanceRequester
|
||||
// The line below blocks and waits for the future to resolve.
|
||||
return try {
|
||||
rpc.startFlow(::CashIssueFlow, amount, issueToParty, issuerBankParty, issuerBankPartyRef, notaryNode.notaryIdentity, anonymous).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashIssueFlow, amount, issuerBankPartyRef, notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
rpc.startFlow(::CashPaymentFlow, amount, issueToParty, params.anonymous)
|
||||
.returnValue.getOrThrow().stx
|
||||
logger.info("Issue request completed successfully: $params")
|
||||
Response.status(Response.Status.CREATED).build()
|
||||
} catch (e: Exception) {
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.millis
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
@ -27,7 +28,9 @@ class TraderDemoTest : NodeBasedTest() {
|
||||
@Test
|
||||
fun `runs trader demo`() {
|
||||
val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>()))
|
||||
val bankUser = User("user1", "test", permissions = setOf(startFlowPermission<CashIssueFlow>(),
|
||||
val bankUser = User("user1", "test", permissions = setOf(
|
||||
startFlowPermission<CashIssueFlow>(),
|
||||
startFlowPermission<CashPaymentFlow>(),
|
||||
startFlowPermission<CommercialPaperIssueFlow>()))
|
||||
val (nodeA, nodeB, bankNode) = listOf(
|
||||
startNode(DUMMY_BANK_A.name, rpcUsers = listOf(demoUser)),
|
||||
|
@ -16,6 +16,7 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.finance.USD
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.services.vault.VaultSchemaV1
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.contracts.calculateRandomlySizedAmounts
|
||||
@ -52,10 +53,10 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
||||
?: throw IllegalStateException("Unable to locate notary node in network map cache")
|
||||
val amounts = calculateRandomlySizedAmounts(amount, 3, 10, Random())
|
||||
val anonymous = false
|
||||
// issue random amounts of currency up to the requested amount, in parallel
|
||||
rpc.startFlow(::CashIssueFlow, amount, OpaqueBytes.of(1), notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||
// pay random amounts of currency up to the requested amount, in parallel
|
||||
val resultFutures = amounts.map { pennies ->
|
||||
rpc.startFlow(::CashIssueFlow, amount.copy(quantity = pennies), buyer, rpc.nodeIdentity().legalIdentity,
|
||||
OpaqueBytes.of(1), notaryNode.notaryIdentity, anonymous).returnValue
|
||||
rpc.startFlow(::CashPaymentFlow, amount.copy(quantity = pennies), buyer, anonymous).returnValue
|
||||
}
|
||||
|
||||
resultFutures.transpose().getOrThrow()
|
||||
|
@ -38,8 +38,7 @@ class ExplorerSimulation(val options: OptionSet) {
|
||||
val manager = User("manager", "test", permissions = setOf(
|
||||
startFlowPermission<CashIssueFlow>(),
|
||||
startFlowPermission<CashPaymentFlow>(),
|
||||
startFlowPermission<CashExitFlow>(),
|
||||
startFlowPermission<IssuerFlow.IssuanceRequester>())
|
||||
startFlowPermission<CashExitFlow>())
|
||||
)
|
||||
|
||||
lateinit var notaryNode: NodeHandle
|
||||
|
@ -36,8 +36,9 @@ import net.corda.explorer.views.bigDecimalFormatter
|
||||
import net.corda.explorer.views.byteFormatter
|
||||
import net.corda.explorer.views.stringConverter
|
||||
import net.corda.flows.AbstractCashFlow
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.flows.CashFlowCommand
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import org.controlsfx.dialog.ExceptionDialog
|
||||
import tornadofx.*
|
||||
import java.math.BigDecimal
|
||||
@ -94,12 +95,13 @@ class NewTransaction : Fragment() {
|
||||
show()
|
||||
}
|
||||
val handle: FlowHandle<AbstractCashFlow.Result> = if (command is CashFlowCommand.IssueCash) {
|
||||
rpcProxy.value!!.startFlow(::IssuanceRequester,
|
||||
rpcProxy.value!!.startFlow(::CashIssueFlow,
|
||||
command.amount,
|
||||
command.issueRef,
|
||||
command.notary)
|
||||
rpcProxy.value!!.startFlow(::CashPaymentFlow,
|
||||
command.amount,
|
||||
command.recipient,
|
||||
command.issueRef,
|
||||
myIdentity.value!!.legalIdentity,
|
||||
command.notary,
|
||||
command.anonymous)
|
||||
} else {
|
||||
command.startFlow(rpcProxy.value!!)
|
||||
|
@ -118,7 +118,7 @@ class VerifierTests {
|
||||
val alice = aliceFuture.get()
|
||||
val notary = notaryFuture.get()
|
||||
startVerifier(notary)
|
||||
alice.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), alice.nodeInfo.legalIdentity, notaryFuture.get().nodeInfo.notaryIdentity).returnValue.get()
|
||||
alice.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), notaryFuture.get().nodeInfo.notaryIdentity).returnValue.get()
|
||||
notary.waitUntilNumberOfVerifiers(1)
|
||||
for (i in 1..10) {
|
||||
alice.rpc.startFlow(::CashPaymentFlow, 10.DOLLARS, alice.nodeInfo.legalIdentity).returnValue.get()
|
||||
|
Loading…
Reference in New Issue
Block a user