mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
FlowException serialised over RPC (subtypes are flattened), and improvement to startFlow RPC for correct exception handling
This commit is contained in:
@ -6,6 +6,7 @@ import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.div
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.Emoji
|
||||
@ -83,9 +84,9 @@ fun sender(rpc: CordaRPCOps) {
|
||||
// Send the transaction to the other recipient
|
||||
val stx = ptx.toSignedTransaction()
|
||||
println("Sending ${stx.id}")
|
||||
val protocolHandle = rpc.startFlow(::FinalityFlow, stx, setOf(otherSide))
|
||||
protocolHandle.progress.subscribe(::println)
|
||||
protocolHandle.returnValue.toBlocking().first()
|
||||
val flowHandle = rpc.startFlow(::FinalityFlow, stx, setOf(otherSide))
|
||||
flowHandle.progress.subscribe(::println)
|
||||
flowHandle.returnValue.getOrThrow()
|
||||
}
|
||||
|
||||
fun recipient(rpc: CordaRPCOps) {
|
||||
|
@ -5,7 +5,6 @@ import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
@ -16,7 +15,6 @@ import net.corda.testing.expect
|
||||
import net.corda.testing.expectEvents
|
||||
import net.corda.testing.sequence
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class BankOfCordaRPCClientTest {
|
||||
@Test
|
||||
@ -45,13 +43,12 @@ class BankOfCordaRPCClientTest {
|
||||
val vaultUpdatesBigCorp = bigCorpProxy.vaultAndUpdates().second
|
||||
|
||||
// Kick-off actual Issuer Flow
|
||||
val result = bocProxy.startFlow(
|
||||
bocProxy.startFlow(
|
||||
::IssuanceRequester,
|
||||
1000.DOLLARS,
|
||||
nodeBigCorporation.nodeInfo.legalIdentity,
|
||||
BOC_PARTY_REF,
|
||||
nodeBankOfCorda.nodeInfo.legalIdentity).returnValue.toBlocking().first()
|
||||
assertTrue { result is SignedTransaction }
|
||||
nodeBankOfCorda.nodeInfo.legalIdentity).returnValue.getOrThrow()
|
||||
|
||||
// Check Bank of Corda Vault Updates
|
||||
vaultUpdatesBoc.expectEvents {
|
||||
|
@ -2,14 +2,15 @@ package net.corda.bank.api
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.currency
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.testing.http.HttpApi
|
||||
|
||||
/**
|
||||
@ -43,6 +44,6 @@ class BankOfCordaClientApi(val hostAndPort: HostAndPort) {
|
||||
val amount = Amount(params.amount, currency(params.currency))
|
||||
val issuerToPartyRef = OpaqueBytes.of(params.issueToPartyRefAsString.toByte())
|
||||
|
||||
return proxy.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty).returnValue.toBlocking().first()
|
||||
return proxy.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty).returnValue.getOrThrow()
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package net.corda.bank.api
|
||||
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.currency
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import java.time.LocalDateTime
|
||||
import javax.ws.rs.*
|
||||
import javax.ws.rs.core.MediaType
|
||||
@ -46,12 +47,13 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
||||
|
||||
// invoke client side of Issuer Flow: IssuanceRequester
|
||||
// The line below blocks and waits for the future to resolve.
|
||||
val result = rpc.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty).returnValue.toBlocking().first()
|
||||
if (result is SignedTransaction) {
|
||||
logger.info("Issue request completed successfully: ${params}")
|
||||
return Response.status(Response.Status.CREATED).build()
|
||||
} else {
|
||||
return Response.status(Response.Status.BAD_REQUEST).build()
|
||||
val status = try {
|
||||
rpc.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty).returnValue.getOrThrow()
|
||||
logger.info("Issue request completed successfully: $params")
|
||||
Response.Status.CREATED
|
||||
} catch (e: FlowException) {
|
||||
Response.Status.BAD_REQUEST
|
||||
}
|
||||
return Response.status(status).build()
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package net.corda.irs.api
|
||||
|
||||
import net.corda.core.contracts.filterStatesOfType
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.loggerFor
|
||||
@ -66,12 +67,12 @@ class InterestRateSwapAPI(val rpc: CordaRPCOps) {
|
||||
@Path("deals")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
fun storeDeal(newDeal: InterestRateSwap.State): Response {
|
||||
try {
|
||||
rpc.startFlow(AutoOfferFlow::Requester, newDeal).returnValue.toBlocking().first()
|
||||
return Response.created(URI.create(generateDealLink(newDeal))).build()
|
||||
return try {
|
||||
rpc.startFlow(AutoOfferFlow::Requester, newDeal).returnValue.getOrThrow()
|
||||
Response.created(URI.create(generateDealLink(newDeal))).build()
|
||||
} catch (ex: Throwable) {
|
||||
logger.info("Exception when creating deal: $ex")
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.toString()).build()
|
||||
Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.toString()).build()
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,7 +95,7 @@ class InterestRateSwapAPI(val rpc: CordaRPCOps) {
|
||||
val priorDemoDate = fetchDemoDate()
|
||||
// Can only move date forwards
|
||||
if (newDemoDate.isAfter(priorDemoDate)) {
|
||||
rpc.startFlow(UpdateBusinessDayFlow::Broadcast, newDemoDate).returnValue.toBlocking().first()
|
||||
rpc.startFlow(UpdateBusinessDayFlow::Broadcast, newDemoDate).returnValue.getOrThrow()
|
||||
return Response.ok().build()
|
||||
}
|
||||
val msg = "demodate is already $priorDemoDate and can only be updated with a later date"
|
||||
@ -113,7 +114,7 @@ class InterestRateSwapAPI(val rpc: CordaRPCOps) {
|
||||
@Path("restart")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
fun exitServer(): Response {
|
||||
rpc.startFlow(ExitServerFlow::Broadcast, 83).returnValue.toBlocking().first()
|
||||
rpc.startFlow(ExitServerFlow::Broadcast, 83).returnValue.getOrThrow()
|
||||
return Response.ok().build()
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package net.corda.notarydemo
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.div
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -60,9 +62,9 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
|
||||
*/
|
||||
private fun buildTransactions(count: Int): List<SignedTransaction> {
|
||||
val moveTransactions = (1..count).map {
|
||||
rpc.startFlow(::DummyIssueAndMove, notary, counterpartyNode.legalIdentity).returnValue.toBlocking().toFuture()
|
||||
rpc.startFlow(::DummyIssueAndMove, notary, counterpartyNode.legalIdentity).returnValue
|
||||
}
|
||||
return moveTransactions.map { it.get() }
|
||||
return Futures.allAsList(moveTransactions).getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,10 +74,8 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
|
||||
* @return a list of encoded signer public keys - one for every transaction
|
||||
*/
|
||||
private fun notariseTransactions(transactions: List<SignedTransaction>): List<String> {
|
||||
val signatureFutures = transactions.map {
|
||||
rpc.startFlow(NotaryFlow::Client, it).returnValue.toBlocking().toFuture()
|
||||
}
|
||||
return signatureFutures.map { it.get().by.toStringShort() }
|
||||
val signatureFutures = transactions.map { rpc.startFlow(NotaryFlow::Client, it).returnValue }
|
||||
return Futures.allAsList(signatureFutures).getOrThrow().map { it.by.toStringShort() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.contracts.filterStatesOfType
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.vega.analytics.InitialMarginTriple
|
||||
@ -159,7 +160,7 @@ class PortfolioApi(val rpc: CordaRPCOps) {
|
||||
return withParty(partyName) {
|
||||
val buyer = if (swap.buySell.isBuy) ownParty else it
|
||||
val seller = if (swap.buySell.isSell) ownParty else it
|
||||
rpc.startFlow(IRSTradeFlow::Requester, swap.toData(buyer, seller), it).returnValue.toBlocking().first()
|
||||
rpc.startFlow(IRSTradeFlow::Requester, swap.toData(buyer, seller), it).returnValue.getOrThrow()
|
||||
Response.accepted().entity("{}").build()
|
||||
}
|
||||
}
|
||||
@ -266,12 +267,12 @@ class PortfolioApi(val rpc: CordaRPCOps) {
|
||||
fun startPortfolioCalculations(params: ValuationCreationParams = ValuationCreationParams(LocalDate.of(2016, 6, 6)), @PathParam("party") partyName: String): Response {
|
||||
return withParty(partyName) { otherParty ->
|
||||
val existingSwap = getPortfolioWith(otherParty)
|
||||
if (existingSwap == null) {
|
||||
rpc.startFlow(SimmFlow::Requester, otherParty, params.valuationDate).returnValue.toBlocking().first()
|
||||
val flowHandle = if (existingSwap == null) {
|
||||
rpc.startFlow(SimmFlow::Requester, otherParty, params.valuationDate)
|
||||
} else {
|
||||
val handle = rpc.startFlow(SimmRevaluation::Initiator, getPortfolioStateAndRefWith(otherParty).ref, params.valuationDate)
|
||||
handle.returnValue.toBlocking().first()
|
||||
rpc.startFlow(SimmRevaluation::Initiator, getPortfolioStateAndRefWith(otherParty).ref, params.valuationDate)
|
||||
}
|
||||
flowHandle.returnValue.getOrThrow()
|
||||
|
||||
withPortfolio(otherParty) { portfolioState ->
|
||||
val portfolio = portfolioState.portfolio.toStateAndRef<IRSState>(rpc).toPortfolio()
|
||||
|
@ -1,19 +1,17 @@
|
||||
package net.corda.traderdemo
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import net.corda.contracts.testing.calculateRandomlySizedAmounts
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.Emoji
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.testing.BOC
|
||||
import net.corda.testing.http.HttpApi
|
||||
import net.corda.traderdemo.flow.SellerFlow
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
@ -26,20 +24,17 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
||||
val logger = loggerFor<TraderDemoClientApi>()
|
||||
}
|
||||
|
||||
fun runBuyer(amount: Amount<Currency> = 30000.0.DOLLARS, notary: String = "Notary"): Boolean {
|
||||
fun runBuyer(amount: Amount<Currency> = 30000.0.DOLLARS): Boolean {
|
||||
val bankOfCordaParty = rpc.partyFromName(BOC.name)
|
||||
?: throw Exception("Unable to locate ${BOC.name} in Network Map Service")
|
||||
val me = rpc.nodeIdentity()
|
||||
// TODO: revert back to multiple issue request amounts (3,10) when soft locking implemented
|
||||
val amounts = calculateRandomlySizedAmounts(amount, 1, 1, Random())
|
||||
val handles = amounts.map {
|
||||
rpc.startFlow(::IssuanceRequester, amount, me.legalIdentity, OpaqueBytes.of(1), bankOfCordaParty)
|
||||
}
|
||||
|
||||
handles.forEach {
|
||||
require(it.returnValue.toBlocking().first() is SignedTransaction)
|
||||
val resultFutures = amounts.map {
|
||||
rpc.startFlow(::IssuanceRequester, amount, me.legalIdentity, OpaqueBytes.of(1), bankOfCordaParty).returnValue
|
||||
}
|
||||
|
||||
Futures.allAsList(resultFutures).getOrThrow()
|
||||
return true
|
||||
}
|
||||
|
||||
@ -60,7 +55,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
||||
}
|
||||
|
||||
// The line below blocks and waits for the future to resolve.
|
||||
val stx = rpc.startFlow(::SellerFlow, otherParty, amount).returnValue.toBlocking().first()
|
||||
val stx = rpc.startFlow(::SellerFlow, otherParty, amount).returnValue.getOrThrow()
|
||||
logger.info("Sale completed - we have a happy customer!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(stx.tx)}")
|
||||
return true
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user