Local RPC, demos use RPC, NODE has special privileges

This commit is contained in:
Andras Slemmer
2016-11-18 11:44:29 +00:00
parent bbba7d3f19
commit a601f0abf5
69 changed files with 544 additions and 342 deletions

View File

@ -1,12 +1,17 @@
package net.corda.traderdemo.api
import net.corda.contracts.testing.fillWithSomeTestCash
import net.corda.contracts.testing.calculateRandomlySizedAmounts
import net.corda.core.contracts.DOLLARS
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.core.serialization.OpaqueBytes
import net.corda.core.utilities.Emoji
import net.corda.core.utilities.loggerFor
import net.corda.flows.CashCommand
import net.corda.flows.CashFlow
import net.corda.flows.CashFlowResult
import net.corda.traderdemo.flow.SellerFlow
import java.util.*
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
@ -14,7 +19,7 @@ import kotlin.test.assertEquals
// API is accessible from /api/traderdemo. All paths specified below are relative to it.
@Path("traderdemo")
class TraderDemoApi(val services: ServiceHub) {
class TraderDemoApi(val rpc: CordaRPCOps) {
data class TestCashParams(val amount: Int, val notary: String)
data class SellParams(val amount: Int)
private companion object {
@ -29,10 +34,20 @@ class TraderDemoApi(val services: ServiceHub) {
@Path("create-test-cash")
@Consumes(MediaType.APPLICATION_JSON)
fun createTestCash(params: TestCashParams): Response {
val notary = services.networkMapCache.notaryNodes.single { it.legalIdentity.name == params.notary }.notaryIdentity
services.fillWithSomeTestCash(params.amount.DOLLARS,
outputNotary = notary,
ownedBy = services.myInfo.legalIdentity.owningKey)
val notary = rpc.networkMapUpdates().first.first { it.legalIdentity.name == params.notary }
val me = rpc.nodeIdentity()
val amounts = calculateRandomlySizedAmounts(params.amount.DOLLARS, 3, 10, Random())
val handles = amounts.map {
rpc.startFlow(::CashFlow, CashCommand.IssueCash(
amount = params.amount.DOLLARS,
issueRef = OpaqueBytes.of(1),
recipient = me.legalIdentity,
notary = notary.notaryIdentity
))
}
handles.forEach {
require(it.returnValue.toBlocking().first() is CashFlowResult.Success)
}
return Response.status(Response.Status.CREATED).build()
}
@ -40,7 +55,7 @@ class TraderDemoApi(val services: ServiceHub) {
@Path("{party}/sell-cash")
@Consumes(MediaType.APPLICATION_JSON)
fun sellCash(params: SellParams, @PathParam("party") partyName: String): Response {
val otherParty = services.identityService.partyFromName(partyName)
val otherParty = rpc.partyFromName(partyName)
if (otherParty != null) {
// The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash.
//
@ -48,15 +63,15 @@ class TraderDemoApi(val services: ServiceHub) {
// attachment. Make sure we have the transaction prospectus attachment loaded into our store.
//
// This can also be done via an HTTP upload, but here we short-circuit and do it from code.
if (services.storageService.attachments.openAttachment(SellerFlow.PROSPECTUS_HASH) == null) {
if (!rpc.attachmentExists(SellerFlow.PROSPECTUS_HASH)) {
javaClass.classLoader.getResourceAsStream("bank-of-london-cp.jar").use {
val id = services.storageService.attachments.importAttachment(it)
val id = rpc.uploadAttachment(it)
assertEquals(SellerFlow.PROSPECTUS_HASH, id)
}
}
// The line below blocks and waits for the future to resolve.
val stx = services.invokeFlowAsync<SignedTransaction>(SellerFlow::class.java, otherParty, params.amount.DOLLARS).resultFuture.get()
val stx = rpc.startFlow(::SellerFlow, otherParty, params.amount.DOLLARS).returnValue.toBlocking().first()
logger.info("Sale completed - we have a happy customer!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(stx.tx)}")
return Response.status(Response.Status.OK).build()
} else {

View File

@ -18,7 +18,9 @@ import java.util.*
class SellerFlow(val otherParty: Party,
val amount: Amount<Currency>,
override val progressTracker: ProgressTracker = tracker()) : FlowLogic<SignedTransaction>() {
override val progressTracker: ProgressTracker) : FlowLogic<SignedTransaction>() {
constructor(otherParty: Party, amount: Amount<Currency>) : this(otherParty, amount, tracker())
companion object {
val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9")

View File

@ -6,13 +6,14 @@ import net.corda.core.node.CordaPluginRegistry
import net.corda.traderdemo.api.TraderDemoApi
import net.corda.traderdemo.flow.BuyerFlow
import net.corda.traderdemo.flow.SellerFlow
import java.util.function.Function
class TraderDemoPlugin : CordaPluginRegistry() {
// A list of classes that expose web APIs.
override val webApis: List<Class<*>> = listOf(TraderDemoApi::class.java)
// A list of flows that are required for this cordapp
override val webApis = listOf(Function(::TraderDemoApi))
// A list of Flows that are required for this cordapp
override val requiredFlows: Map<String, Set<String>> = mapOf(
SellerFlow::class.java.name to setOf(Party::class.java.name, Amount::class.java.name)
)
override val servicePlugins: List<Class<*>> = listOf(BuyerFlow.Service::class.java)
override val servicePlugins = listOf(Function(BuyerFlow::Service))
}

View File

@ -1,2 +1,2 @@
# Register a ServiceLoader service extending from net.corda.node.CordaPluginRegistry
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
net.corda.traderdemo.plugin.TraderDemoPlugin