FlowException serialised over RPC (subtypes are flattened), and improvement to startFlow RPC for correct exception handling

This commit is contained in:
Shams Asari
2017-02-01 21:27:06 +00:00
parent 56dbf1e844
commit b86c80691e
26 changed files with 261 additions and 143 deletions

View File

@ -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) {

View File

@ -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 {

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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() }
}
}

View File

@ -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()

View File

@ -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 {