mirror of
https://github.com/corda/corda.git
synced 2025-01-27 06:39:38 +00:00
De-issuerify the cash payment flow. This makes it easier to use the payment flow from the shell.
This commit is contained in:
parent
4f6b44ceff
commit
afbc8f9b5c
@ -1,7 +1,6 @@
|
|||||||
package net.corda.client
|
package net.corda.client
|
||||||
|
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.issuedBy
|
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
@ -85,10 +84,7 @@ class CordaRPCClientTest : NodeBasedTest() {
|
|||||||
fun `FlowException thrown by flow`() {
|
fun `FlowException thrown by flow`() {
|
||||||
client.start(rpcUser.username, rpcUser.password)
|
client.start(rpcUser.username, rpcUser.password)
|
||||||
val proxy = client.proxy()
|
val proxy = client.proxy()
|
||||||
val handle = proxy.startFlow(::CashPaymentFlow,
|
val handle = proxy.startFlow(::CashPaymentFlow, 100.DOLLARS, node.info.legalIdentity)
|
||||||
100.DOLLARS.issuedBy(node.info.legalIdentity.ref(1)),
|
|
||||||
node.info.legalIdentity
|
|
||||||
)
|
|
||||||
// TODO Restrict this to CashException once RPC serialisation has been fixed
|
// TODO Restrict this to CashException once RPC serialisation has been fixed
|
||||||
assertThatExceptionOfType(FlowException::class.java).isThrownBy {
|
assertThatExceptionOfType(FlowException::class.java).isThrownBy {
|
||||||
handle.returnValue.getOrThrow()
|
handle.returnValue.getOrThrow()
|
||||||
|
@ -4,8 +4,7 @@ import net.corda.client.model.NodeMonitorModel
|
|||||||
import net.corda.client.model.ProgressTrackingEvent
|
import net.corda.client.model.ProgressTrackingEvent
|
||||||
import net.corda.core.bufferUntilSubscribed
|
import net.corda.core.bufferUntilSubscribed
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.PartyAndReference
|
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
@ -123,17 +122,8 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `cash issue and move`() {
|
fun `cash issue and move`() {
|
||||||
rpc.startFlow(::CashIssueFlow,
|
rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), aliceNode.legalIdentity, notaryNode.notaryIdentity).returnValue.getOrThrow()
|
||||||
Amount(100, USD),
|
rpc.startFlow(::CashPaymentFlow, 100.DOLLARS, aliceNode.legalIdentity).returnValue.getOrThrow()
|
||||||
OpaqueBytes(ByteArray(1, { 1 })),
|
|
||||||
aliceNode.legalIdentity,
|
|
||||||
notaryNode.notaryIdentity
|
|
||||||
).returnValue.getOrThrow()
|
|
||||||
|
|
||||||
rpc.startFlow(::CashPaymentFlow,
|
|
||||||
Amount(100, Issued(PartyAndReference(aliceNode.legalIdentity, OpaqueBytes(ByteArray(1, { 1 }))), USD)),
|
|
||||||
aliceNode.legalIdentity
|
|
||||||
)
|
|
||||||
|
|
||||||
var issueSmId: StateMachineRunId? = null
|
var issueSmId: StateMachineRunId? = null
|
||||||
var moveSmId: StateMachineRunId? = null
|
var moveSmId: StateMachineRunId? = null
|
||||||
|
@ -73,11 +73,9 @@ class EventGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val moveCashGenerator =
|
val moveCashGenerator =
|
||||||
amountIssuedGenerator.combine(
|
amountIssuedGenerator.combine(partyGenerator) { amountIssued, recipient ->
|
||||||
partyGenerator
|
|
||||||
) { amountIssued, recipient ->
|
|
||||||
CashFlowCommand.PayCash(
|
CashFlowCommand.PayCash(
|
||||||
amount = amountIssued,
|
amount = amountIssued.withoutIssuer(),
|
||||||
recipient = recipient
|
recipient = recipient
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,7 @@ package net.corda.core.contracts
|
|||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
|
|
||||||
class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException() {
|
class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException("Insufficient balance, missing $amountMissing")
|
||||||
override fun toString() = "Insufficient balance, missing $amountMissing"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for contract states representing assets which are fungible, countable and issued by a
|
* Interface for contract states representing assets which are fungible, countable and issued by a
|
||||||
|
@ -4,13 +4,11 @@ import com.google.common.util.concurrent.Futures
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.issuedBy
|
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.core.toFuture
|
|
||||||
import net.corda.flows.CashIssueFlow
|
import net.corda.flows.CashIssueFlow
|
||||||
import net.corda.flows.CashPaymentFlow
|
import net.corda.flows.CashPaymentFlow
|
||||||
import net.corda.node.driver.driver
|
import net.corda.node.driver.driver
|
||||||
@ -92,10 +90,7 @@ class IntegrationTestingTutorial {
|
|||||||
|
|
||||||
// START 5
|
// START 5
|
||||||
for (i in 1 .. 10) {
|
for (i in 1 .. 10) {
|
||||||
bobProxy.startFlow(::CashPaymentFlow,
|
bobProxy.startFlow(::CashPaymentFlow, i.DOLLARS, alice.nodeInfo.legalIdentity).returnValue.getOrThrow()
|
||||||
i.DOLLARS.issuedBy(alice.nodeInfo.legalIdentity.ref(issueRef)),
|
|
||||||
alice.nodeInfo.legalIdentity
|
|
||||||
).returnValue.getOrThrow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aliceVaultUpdates.expectEvents {
|
aliceVaultUpdates.expectEvents {
|
||||||
|
@ -122,7 +122,7 @@ fun generateTransactions(proxy: CordaRPCOps) {
|
|||||||
ownedQuantity -= quantity
|
ownedQuantity -= quantity
|
||||||
} else if (ownedQuantity > 1000 && n < 0.7) {
|
} else if (ownedQuantity > 1000 && n < 0.7) {
|
||||||
val quantity = Math.abs(random.nextLong() % Math.min(ownedQuantity, 2000))
|
val quantity = Math.abs(random.nextLong() % Math.min(ownedQuantity, 2000))
|
||||||
proxy.startFlow(::CashPaymentFlow, Amount(quantity, Issued(meAndRef, USD)), me)
|
proxy.startFlow(::CashPaymentFlow, Amount(quantity, USD), me)
|
||||||
} else {
|
} else {
|
||||||
val quantity = Math.abs(random.nextLong() % 1000)
|
val quantity = Math.abs(random.nextLong() % 1000)
|
||||||
proxy.startFlow(::CashIssueFlow, Amount(quantity, USD), issueRef, me, notary)
|
proxy.startFlow(::CashIssueFlow, Amount(quantity, USD), issueRef, me, notary)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.corda.flows
|
package net.corda.flows
|
||||||
|
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.Issued
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.FlowHandle
|
import net.corda.core.messaging.FlowHandle
|
||||||
@ -11,7 +10,7 @@ import net.corda.core.transactions.SignedTransaction
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command to initiate the Cash flow with.
|
* A command to initiate the cash flow with.
|
||||||
*/
|
*/
|
||||||
sealed class CashFlowCommand {
|
sealed class CashFlowCommand {
|
||||||
abstract fun startFlow(proxy: CordaRPCOps): FlowHandle<SignedTransaction>
|
abstract fun startFlow(proxy: CordaRPCOps): FlowHandle<SignedTransaction>
|
||||||
@ -32,7 +31,7 @@ sealed class CashFlowCommand {
|
|||||||
* @param amount the amount of currency to issue on to the ledger.
|
* @param amount the amount of currency to issue on to the ledger.
|
||||||
* @param recipient the party to issue the cash to.
|
* @param recipient the party to issue the cash to.
|
||||||
*/
|
*/
|
||||||
class PayCash(val amount: Amount<Issued<Currency>>, val recipient: Party) : CashFlowCommand() {
|
class PayCash(val amount: Amount<Currency>, val recipient: Party, val issuerConstraint: Party? = null) : CashFlowCommand() {
|
||||||
override fun startFlow(proxy: CordaRPCOps) = proxy.startFlow(::CashPaymentFlow, amount, recipient)
|
override fun startFlow(proxy: CordaRPCOps) = proxy.startFlow(::CashPaymentFlow, amount, recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.corda.flows
|
package net.corda.flows
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.Amount
|
||||||
|
import net.corda.core.contracts.InsufficientBalanceException
|
||||||
|
import net.corda.core.contracts.TransactionType
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.keys
|
import net.corda.core.crypto.keys
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
@ -12,13 +14,19 @@ import java.security.KeyPair
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a flow that produces an cash move transaction.
|
* Initiates a flow that sends cash to a recipient.
|
||||||
*
|
*
|
||||||
* @param amount the amount of a currency to pay to the recipient.
|
* @param amount the amount of a currency to pay to the recipient.
|
||||||
* @param recipient the party to pay the currency to.
|
* @param recipient the party to pay the currency to.
|
||||||
|
* @param issuerConstraint if specified, the payment will be made using only cash issued by the given parties.
|
||||||
*/
|
*/
|
||||||
open class CashPaymentFlow(val amount: Amount<Issued<Currency>>, val recipient: Party, progressTracker: ProgressTracker) : AbstractCashFlow(progressTracker) {
|
open class CashPaymentFlow(
|
||||||
constructor(amount: Amount<Issued<Currency>>, recipient: Party) : this(amount, recipient, tracker())
|
val amount: Amount<Currency>,
|
||||||
|
val recipient: Party,
|
||||||
|
progressTracker: ProgressTracker,
|
||||||
|
val issuerConstraint: Set<Party>? = null) : AbstractCashFlow(progressTracker) {
|
||||||
|
/** A straightforward constructor that constructs spends using cash states of any issuer. */
|
||||||
|
constructor(amount: Amount<Currency>, recipient: Party) : this(amount, recipient, tracker())
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): SignedTransaction {
|
override fun call(): SignedTransaction {
|
||||||
@ -28,11 +36,11 @@ open class CashPaymentFlow(val amount: Amount<Issued<Currency>>, val recipient:
|
|||||||
val (spendTX, keysForSigning) = try {
|
val (spendTX, keysForSigning) = try {
|
||||||
serviceHub.vaultService.generateSpend(
|
serviceHub.vaultService.generateSpend(
|
||||||
builder,
|
builder,
|
||||||
amount.withoutIssuer(),
|
amount,
|
||||||
recipient.owningKey,
|
recipient.owningKey,
|
||||||
setOf(amount.token.issuer.party))
|
issuerConstraint)
|
||||||
} catch (e: InsufficientBalanceException) {
|
} catch (e: InsufficientBalanceException) {
|
||||||
throw CashException("Insufficient cash for spend", e)
|
throw CashException("Insufficient cash for spend: ${e.message}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
progressTracker.currentStep = SIGNING_TX
|
progressTracker.currentStep = SIGNING_TX
|
||||||
|
@ -89,7 +89,7 @@ object IssuerFlow {
|
|||||||
return issueTx
|
return issueTx
|
||||||
// now invoke Cash subflow to Move issued assetType to issue requester
|
// now invoke Cash subflow to Move issued assetType to issue requester
|
||||||
progressTracker.currentStep = TRANSFERRING
|
progressTracker.currentStep = TRANSFERRING
|
||||||
val moveCashFlow = CashPaymentFlow(amount.issuedBy(bankOfCordaParty.ref(issuerPartyRef)), issueTo)
|
val moveCashFlow = CashPaymentFlow(amount, issueTo)
|
||||||
val moveTx = subFlow(moveCashFlow)
|
val moveTx = subFlow(moveCashFlow)
|
||||||
// NOTE: CashFlow PayCash calls FinalityFlow which performs a Broadcast (which stores a local copy of the txn to the ledger)
|
// NOTE: CashFlow PayCash calls FinalityFlow which performs a Broadcast (which stores a local copy of the txn to the ledger)
|
||||||
return moveTx
|
return moveTx
|
||||||
|
@ -144,9 +144,7 @@ class DistributedServiceTests : DriverBasedTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun paySelf(amount: Amount<Currency>) {
|
private fun paySelf(amount: Amount<Currency>) {
|
||||||
val payHandle = aliceProxy.startFlow(
|
val payHandle = aliceProxy.startFlow(::CashPaymentFlow, amount, alice.nodeInfo.legalIdentity)
|
||||||
::CashPaymentFlow,
|
|
||||||
amount.issuedBy(alice.nodeInfo.legalIdentity.ref(0)), alice.nodeInfo.legalIdentity)
|
|
||||||
payHandle.returnValue.getOrThrow()
|
payHandle.returnValue.getOrThrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,10 +126,7 @@ class CordaRPCOpsImplTest {
|
|||||||
|
|
||||||
network.runNetwork()
|
network.runNetwork()
|
||||||
|
|
||||||
rpc.startFlow(::CashPaymentFlow,
|
rpc.startFlow(::CashPaymentFlow, Amount(100, USD), aliceNode.info.legalIdentity)
|
||||||
Amount(100, Issued(PartyAndReference(aliceNode.info.legalIdentity, OpaqueBytes(ByteArray(1, { 1 }))), USD)),
|
|
||||||
aliceNode.info.legalIdentity
|
|
||||||
)
|
|
||||||
|
|
||||||
network.runNetwork()
|
network.runNetwork()
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import com.google.common.util.concurrent.ListenableFuture
|
|||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.DummyState
|
import net.corda.core.contracts.DummyState
|
||||||
import net.corda.core.contracts.issuedBy
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
@ -326,9 +325,7 @@ class StateMachineManagerTests {
|
|||||||
notary1.info.notaryIdentity))
|
notary1.info.notaryIdentity))
|
||||||
// We pay a couple of times, the notary picking should go round robin
|
// We pay a couple of times, the notary picking should go round robin
|
||||||
for (i in 1 .. 3) {
|
for (i in 1 .. 3) {
|
||||||
node1.services.startFlow(CashPaymentFlow(
|
node1.services.startFlow(CashPaymentFlow(500.DOLLARS, node2.info.legalIdentity))
|
||||||
500.DOLLARS.issuedBy(node1.info.legalIdentity.ref(0x01)),
|
|
||||||
node2.info.legalIdentity))
|
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
}
|
}
|
||||||
val endpoint = net.messagingNetwork.endpoint(notary1.net.myAddress as InMemoryMessagingNetwork.PeerHandle)!!
|
val endpoint = net.messagingNetwork.endpoint(notary1.net.myAddress as InMemoryMessagingNetwork.PeerHandle)!!
|
||||||
|
@ -18,8 +18,6 @@ import net.corda.client.fxutils.map
|
|||||||
import net.corda.client.fxutils.unique
|
import net.corda.client.fxutils.unique
|
||||||
import net.corda.client.model.*
|
import net.corda.client.model.*
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.Issued
|
|
||||||
import net.corda.core.contracts.PartyAndReference
|
|
||||||
import net.corda.core.contracts.withoutIssuer
|
import net.corda.core.contracts.withoutIssuer
|
||||||
import net.corda.core.crypto.AbstractParty
|
import net.corda.core.crypto.AbstractParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
@ -148,7 +146,7 @@ class NewTransaction : Fragment() {
|
|||||||
CashTransaction.Issue -> {
|
CashTransaction.Issue -> {
|
||||||
CashFlowCommand.IssueCash(Amount(amount.value, currencyChoiceBox.value), issueRef, partyBChoiceBox.value.legalIdentity, notaries.first().notaryIdentity)
|
CashFlowCommand.IssueCash(Amount(amount.value, currencyChoiceBox.value), issueRef, partyBChoiceBox.value.legalIdentity, notaries.first().notaryIdentity)
|
||||||
}
|
}
|
||||||
CashTransaction.Pay -> CashFlowCommand.PayCash(Amount(amount.value, Issued(PartyAndReference(issuerChoiceBox.value, issueRef), currencyChoiceBox.value)), partyBChoiceBox.value.legalIdentity)
|
CashTransaction.Pay -> CashFlowCommand.PayCash(Amount(amount.value, currencyChoiceBox.value), partyBChoiceBox.value.legalIdentity)
|
||||||
CashTransaction.Exit -> CashFlowCommand.ExitCash(Amount(amount.value, currencyChoiceBox.value), issueRef)
|
CashTransaction.Exit -> CashFlowCommand.ExitCash(Amount(amount.value, currencyChoiceBox.value), issueRef)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,13 @@ package net.corda.loadtest.tests
|
|||||||
import net.corda.client.mock.Generator
|
import net.corda.client.mock.Generator
|
||||||
import net.corda.client.mock.pickN
|
import net.corda.client.mock.pickN
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.*
|
|
||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.Issued
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
import net.corda.core.crypto.AbstractParty
|
import net.corda.core.crypto.AbstractParty
|
||||||
import net.corda.core.crypto.AnonymousParty
|
import net.corda.core.failure
|
||||||
import net.corda.core.flows.FlowException
|
|
||||||
import net.corda.core.messaging.startFlow
|
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.flows.CashException
|
import net.corda.core.success
|
||||||
import net.corda.flows.CashFlowCommand
|
import net.corda.flows.CashFlowCommand
|
||||||
import net.corda.loadtest.LoadTest
|
import net.corda.loadtest.LoadTest
|
||||||
import net.corda.loadtest.NodeHandle
|
import net.corda.loadtest.NodeHandle
|
||||||
@ -125,7 +122,7 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
|||||||
val quantities = state.nodeVaults[node.info.legalIdentity] ?: mapOf()
|
val quantities = state.nodeVaults[node.info.legalIdentity] ?: mapOf()
|
||||||
val possibleRecipients = nodeMap.keys.toList()
|
val possibleRecipients = nodeMap.keys.toList()
|
||||||
val moves = quantities.map {
|
val moves = quantities.map {
|
||||||
it.value.toDouble() / 1000 to generateMove(it.value, USD, it.key.toAnonymous(), possibleRecipients)
|
it.value.toDouble() / 1000 to generateMove(it.value, USD, node.info.legalIdentity, possibleRecipients)
|
||||||
}
|
}
|
||||||
val exits = quantities.mapNotNull {
|
val exits = quantities.mapNotNull {
|
||||||
if (it.key == node.info.legalIdentity) {
|
if (it.key == node.info.legalIdentity) {
|
||||||
@ -160,26 +157,26 @@ val crossCashTest = LoadTest<CrossCashCommand, CrossCashState>(
|
|||||||
val newDiffQueues = state.copyQueues()
|
val newDiffQueues = state.copyQueues()
|
||||||
val recipientOriginators = newDiffQueues.getOrPut(command.command.recipient, { HashMap() })
|
val recipientOriginators = newDiffQueues.getOrPut(command.command.recipient, { HashMap() })
|
||||||
val senderQuantities = newNodeVaults[command.node.info.legalIdentity]!!
|
val senderQuantities = newNodeVaults[command.node.info.legalIdentity]!!
|
||||||
val quantity = command.command.amount.quantity
|
val amount = command.command.amount
|
||||||
val issuer = command.command.amount.token.issuer.party
|
val issuer = command.command.issuerConstraint!!
|
||||||
val originator = command.node.info.legalIdentity
|
val originator = command.node.info.legalIdentity
|
||||||
val senderQuantity = senderQuantities[issuer] ?: throw Exception(
|
val senderQuantity = senderQuantities[issuer] ?: throw Exception(
|
||||||
"Generated payment of ${command.command.amount} from ${command.node.info.legalIdentity}, " +
|
"Generated payment of ${command.command.amount} from ${command.node.info.legalIdentity}, " +
|
||||||
"however there is no cash from $issuer!"
|
"however there is no cash from $issuer!"
|
||||||
)
|
)
|
||||||
if (senderQuantity < quantity) {
|
if (senderQuantity < amount.quantity) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Generated payment of ${command.command.amount} from ${command.node.info.legalIdentity}, " +
|
"Generated payment of ${command.command.amount} from ${command.node.info.legalIdentity}, " +
|
||||||
"however they only have $senderQuantity!"
|
"however they only have $senderQuantity!"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (senderQuantity == quantity) {
|
if (senderQuantity == amount.quantity) {
|
||||||
senderQuantities.remove(issuer)
|
senderQuantities.remove(issuer)
|
||||||
} else {
|
} else {
|
||||||
senderQuantities.put(issuer, senderQuantity - quantity)
|
senderQuantities.put(issuer, senderQuantity - amount.quantity)
|
||||||
}
|
}
|
||||||
val recipientQueue = recipientOriginators.getOrPut(originator, { ArrayList() })
|
val recipientQueue = recipientOriginators.getOrPut(originator, { ArrayList() })
|
||||||
recipientQueue.add(Pair(issuer, quantity))
|
recipientQueue.add(Pair(issuer, amount.quantity))
|
||||||
CrossCashState(newNodeVaults, newDiffQueues)
|
CrossCashState(newNodeVaults, newDiffQueues)
|
||||||
}
|
}
|
||||||
is CashFlowCommand.ExitCash -> {
|
is CashFlowCommand.ExitCash -> {
|
||||||
|
@ -5,7 +5,7 @@ import net.corda.client.mock.generateAmount
|
|||||||
import net.corda.client.mock.pickOne
|
import net.corda.client.mock.pickOne
|
||||||
import net.corda.core.contracts.Issued
|
import net.corda.core.contracts.Issued
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.crypto.AnonymousParty
|
import net.corda.core.contracts.withoutIssuer
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.flows.CashFlowCommand
|
import net.corda.flows.CashFlowCommand
|
||||||
@ -28,13 +28,13 @@ fun generateIssue(
|
|||||||
fun generateMove(
|
fun generateMove(
|
||||||
max: Long,
|
max: Long,
|
||||||
currency: Currency,
|
currency: Currency,
|
||||||
issuer: AnonymousParty,
|
issuer: Party,
|
||||||
possibleRecipients: List<Party>
|
possibleRecipients: List<Party>
|
||||||
): Generator<CashFlowCommand.PayCash> {
|
): Generator<CashFlowCommand.PayCash> {
|
||||||
return generateAmount(1, max, Generator.pure(Issued(PartyAndReference(issuer, OpaqueBytes.of(0)), currency))).combine(
|
return generateAmount(1, max, Generator.pure(Issued(PartyAndReference(issuer, OpaqueBytes.of(0)), currency))).combine(
|
||||||
Generator.pickOne(possibleRecipients)
|
Generator.pickOne(possibleRecipients)
|
||||||
) { amount, recipient ->
|
) { amount, recipient ->
|
||||||
CashFlowCommand.PayCash(amount, recipient)
|
CashFlowCommand.PayCash(amount.withoutIssuer(), recipient, issuer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user