Apply @Suspendable on all flow methods that call vault generateSpend (#612)

This commit is contained in:
josecoll 2017-05-02 09:38:44 +01:00 committed by GitHub
parent 0612f147be
commit 3d401d1dcb
5 changed files with 62 additions and 6 deletions

View File

@ -1,5 +1,6 @@
package net.corda.contracts;
import co.paralleluniverse.fibers.*;
import com.google.common.collect.*;
import kotlin.*;
import net.corda.contracts.asset.*;
@ -311,6 +312,7 @@ public class JavaCommercialPaper implements Contract {
return generateIssue(issuance, faceValue, maturityDate, notary, null);
}
@Suspendable
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);
tx.addInputState(paper);

View File

@ -1,5 +1,6 @@
package net.corda.contracts
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.sumCashBy
import net.corda.contracts.clause.AbstractIssue
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::class)
@Suspendable
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: VaultService) {
// Add the cash movement using the states in our vault.
val amount = paper.state.data.faceValue.let { amount -> Amount(amount.quantity, amount.token.product) }

View File

@ -1,5 +1,6 @@
package net.corda.contracts
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.sumCashBy
import net.corda.core.contracts.*
import net.corda.core.crypto.NullPublicKey
@ -124,6 +125,7 @@ class CommercialPaperLegacy : Contract {
}
@Throws(InsufficientBalanceException::class)
@Suspendable
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, vault: VaultService) {
// Add the cash movement using the states in our vault.
vault.generateSpend(tx, paper.state.data.faceValue.withoutIssuer(), paper.state.data.owner)

View File

@ -209,6 +209,7 @@ object TwoPartyTradeFlow {
return ptx.toSignedTransaction(checkSufficientSignatures = false)
}
@Suspendable
private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair<TransactionBuilder, List<PublicKey>> {
val ptx = TransactionType.General.Builder(notary)

View File

@ -4,7 +4,9 @@ import net.corda.contracts.CommercialPaper
import net.corda.contracts.asset.*
import net.corda.contracts.testing.fillWithSomeTestCash
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.flows.FlowStateMachine
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.TransactionBuilder
import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.ALICE
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.core.utilities.*
import net.corda.flows.TwoPartyTradeFlow.Buyer
import net.corda.flows.TwoPartyTradeFlow.Seller
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
fun `shutdown and restore`() {
ledger {