mirror of
https://github.com/corda/corda.git
synced 2025-06-17 06:38:21 +00:00
Apply @Suspendable on all flow methods that call vault generateSpend (#612)
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
package net.corda.contracts;
|
package net.corda.contracts;
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.*;
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import kotlin.*;
|
import kotlin.*;
|
||||||
import net.corda.contracts.asset.*;
|
import net.corda.contracts.asset.*;
|
||||||
@ -311,6 +312,7 @@ public class JavaCommercialPaper implements Contract {
|
|||||||
return generateIssue(issuance, faceValue, maturityDate, notary, null);
|
return generateIssue(issuance, faceValue, maturityDate, notary, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
public void generateRedeem(TransactionBuilder tx, StateAndRef<State> paper, VaultService vault) throws InsufficientBalanceException {
|
public void generateRedeem(TransactionBuilder tx, StateAndRef<State> paper, VaultService vault) throws InsufficientBalanceException {
|
||||||
vault.generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), null);
|
vault.generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), null);
|
||||||
tx.addInputState(paper);
|
tx.addInputState(paper);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.contracts
|
package net.corda.contracts
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.contracts.asset.sumCashBy
|
import net.corda.contracts.asset.sumCashBy
|
||||||
import net.corda.contracts.clause.AbstractIssue
|
import net.corda.contracts.clause.AbstractIssue
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
@ -214,6 +215,7 @@ class CommercialPaper : Contract {
|
|||||||
* @throws InsufficientBalanceException if the vault doesn't contain enough money to pay the redeemer.
|
* @throws InsufficientBalanceException if the vault doesn't contain enough money to pay the redeemer.
|
||||||
*/
|
*/
|
||||||
@Throws(InsufficientBalanceException::class)
|
@Throws(InsufficientBalanceException::class)
|
||||||
|
@Suspendable
|
||||||
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: VaultService) {
|
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: VaultService) {
|
||||||
// Add the cash movement using the states in our vault.
|
// Add the cash movement using the states in our vault.
|
||||||
val amount = paper.state.data.faceValue.let { amount -> Amount(amount.quantity, amount.token.product) }
|
val amount = paper.state.data.faceValue.let { amount -> Amount(amount.quantity, amount.token.product) }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.contracts
|
package net.corda.contracts
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.contracts.asset.sumCashBy
|
import net.corda.contracts.asset.sumCashBy
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.NullPublicKey
|
import net.corda.core.crypto.NullPublicKey
|
||||||
@ -124,6 +125,7 @@ class CommercialPaperLegacy : Contract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(InsufficientBalanceException::class)
|
@Throws(InsufficientBalanceException::class)
|
||||||
|
@Suspendable
|
||||||
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: VaultService) {
|
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: VaultService) {
|
||||||
// Add the cash movement using the states in our vault.
|
// Add the cash movement using the states in our vault.
|
||||||
vault.generateSpend(tx, paper.state.data.faceValue.withoutIssuer(), paper.state.data.owner)
|
vault.generateSpend(tx, paper.state.data.faceValue.withoutIssuer(), paper.state.data.owner)
|
||||||
|
@ -209,6 +209,7 @@ object TwoPartyTradeFlow {
|
|||||||
return ptx.toSignedTransaction(checkSufficientSignatures = false)
|
return ptx.toSignedTransaction(checkSufficientSignatures = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
|
private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
|
||||||
val ptx = TransactionType.General.Builder(notary)
|
val ptx = TransactionType.General.Builder(notary)
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ import net.corda.contracts.CommercialPaper
|
|||||||
import net.corda.contracts.asset.*
|
import net.corda.contracts.asset.*
|
||||||
import net.corda.contracts.testing.fillWithSomeTestCash
|
import net.corda.contracts.testing.fillWithSomeTestCash
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.AnonymousParty
|
||||||
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.days
|
import net.corda.core.days
|
||||||
import net.corda.core.flows.FlowStateMachine
|
import net.corda.core.flows.FlowStateMachine
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
@ -16,11 +18,7 @@ import net.corda.core.rootCause
|
|||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.ALICE
|
import net.corda.core.utilities.*
|
||||||
import net.corda.core.utilities.BOB
|
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
|
||||||
import net.corda.core.utilities.LogHelper
|
|
||||||
import net.corda.core.utilities.TEST_TX_TIME
|
|
||||||
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
import net.corda.flows.TwoPartyTradeFlow.Buyer
|
||||||
import net.corda.flows.TwoPartyTradeFlow.Seller
|
import net.corda.flows.TwoPartyTradeFlow.Seller
|
||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
@ -121,6 +119,57 @@ class TwoPartyTradeFlowTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = InsufficientBalanceException::class)
|
||||||
|
fun `trade cash for commercial paper fails using soft locking`() {
|
||||||
|
net = MockNetwork(false, true)
|
||||||
|
|
||||||
|
ledger {
|
||||||
|
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||||
|
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||||
|
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||||
|
val aliceKey = aliceNode.services.legalIdentityKey
|
||||||
|
val notaryKey = notaryNode.services.notaryIdentityKey
|
||||||
|
|
||||||
|
aliceNode.disableDBCloseOnStop()
|
||||||
|
bobNode.disableDBCloseOnStop()
|
||||||
|
|
||||||
|
val cashStates =
|
||||||
|
bobNode.database.transaction {
|
||||||
|
bobNode.services.fillWithSomeTestCash(2000.DOLLARS, notaryNode.info.notaryIdentity, 3, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
val alicesFakePaper = aliceNode.database.transaction {
|
||||||
|
fillUpForSeller(false, aliceNode.info.legalIdentity.owningKey,
|
||||||
|
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null, notaryNode.info.notaryIdentity).second
|
||||||
|
}
|
||||||
|
|
||||||
|
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, aliceKey, notaryKey)
|
||||||
|
|
||||||
|
val cashLockId = UUID.randomUUID()
|
||||||
|
bobNode.database.transaction {
|
||||||
|
// lock the cash states with an arbitrary lockId (to prevent the Buyer flow from claiming the states)
|
||||||
|
bobNode.vault.softLockReserve(cashLockId, cashStates.states.map { it.ref }.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notaryNode, aliceNode, bobNode,
|
||||||
|
"alice's paper".outputStateAndRef())
|
||||||
|
|
||||||
|
assertEquals(aliceResult.getOrThrow(), bobStateMachine.getOrThrow().resultFuture.getOrThrow())
|
||||||
|
|
||||||
|
aliceNode.stop()
|
||||||
|
bobNode.stop()
|
||||||
|
|
||||||
|
aliceNode.database.transaction {
|
||||||
|
assertThat(aliceNode.checkpointStorage.checkpoints()).isEmpty()
|
||||||
|
}
|
||||||
|
aliceNode.manuallyCloseDB()
|
||||||
|
bobNode.database.transaction {
|
||||||
|
assertThat(bobNode.checkpointStorage.checkpoints()).isEmpty()
|
||||||
|
}
|
||||||
|
bobNode.manuallyCloseDB()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `shutdown and restore`() {
|
fun `shutdown and restore`() {
|
||||||
ledger {
|
ledger {
|
||||||
|
Reference in New Issue
Block a user