diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index e7734161f4..a0aa250f88 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -194,14 +194,14 @@ interface CordaRPCOps : RPCOps { * Start the given flow with the given arguments. [logicType] must be annotated with [net.corda.core.flows.StartableByRPC]. */ @RPCReturnsObservables - fun startFlowDynamic(logicType: Class>, vararg args: Any?): FlowHandle + fun startFlowDynamic(logicType: Class>, vararg args: Any?): FlowHandle /** * Start the given flow with the given arguments, returning an [Observable] with a single observation of the * result of running the flow. [logicType] must be annotated with [net.corda.core.flows.StartableByRPC]. */ @RPCReturnsObservables - fun startTrackedFlowDynamic(logicType: Class>, vararg args: Any?): FlowProgressHandle + fun startTrackedFlowDynamic(logicType: Class>, vararg args: Any?): FlowProgressHandle /** * Returns Node's identity, assuming this will not change while the node is running. @@ -327,25 +327,25 @@ inline fun CordaRPCOps.vaultTrackBy(criteria: QueryC * Note that the passed in constructor function is only used for unification of other type parameters and reification of * the Class instance of the flow. This could be changed to use the constructor function directly. */ -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: () -> R ): FlowHandle = startFlowDynamic(R::class.java) -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: (A) -> R, arg0: A ): FlowHandle = startFlowDynamic(R::class.java, arg0) -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: (A, B) -> R, arg0: A, arg1: B ): FlowHandle = startFlowDynamic(R::class.java, arg0, arg1) -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: (A, B, C) -> R, arg0: A, @@ -353,7 +353,7 @@ inline fun > CordaRPCOps.startFlow( arg2: C ): FlowHandle = startFlowDynamic(R::class.java, arg0, arg1, arg2) -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: (A, B, C, D) -> R, arg0: A, @@ -362,7 +362,7 @@ inline fun > CordaRPCOps.startFlow arg3: D ): FlowHandle = startFlowDynamic(R::class.java, arg0, arg1, arg2, arg3) -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: (A, B, C, D, E) -> R, arg0: A, @@ -372,7 +372,7 @@ inline fun > CordaRPCOps.startF arg4: E ): FlowHandle = startFlowDynamic(R::class.java, arg0, arg1, arg2, arg3, arg4) -inline fun > CordaRPCOps.startFlow( +inline fun > CordaRPCOps.startFlow( @Suppress("UNUSED_PARAMETER") flowConstructor: (A, B, C, D, E, F) -> R, arg0: A, @@ -387,20 +387,20 @@ inline fun > CordaRPCOps.sta * Same again, except this time with progress-tracking enabled. */ @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: () -> R ): FlowProgressHandle = startTrackedFlowDynamic(R::class.java) @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: (A) -> R, arg0: A ): FlowProgressHandle = startTrackedFlowDynamic(R::class.java, arg0) @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: (A, B) -> R, arg0: A, @@ -408,7 +408,7 @@ inline fun > CordaRPCOps.startTrackedFlo ): FlowProgressHandle = startTrackedFlowDynamic(R::class.java, arg0, arg1) @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: (A, B, C) -> R, arg0: A, @@ -417,7 +417,7 @@ inline fun > CordaRPCOps.startTracked ): FlowProgressHandle = startTrackedFlowDynamic(R::class.java, arg0, arg1, arg2) @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: (A, B, C, D) -> R, arg0: A, @@ -427,7 +427,7 @@ inline fun > CordaRPCOps.startTrac ): FlowProgressHandle = startTrackedFlowDynamic(R::class.java, arg0, arg1, arg2, arg3) @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: (A, B, C, D, E) -> R, arg0: A, @@ -438,7 +438,7 @@ inline fun > CordaRPCOps.startT ): FlowProgressHandle = startTrackedFlowDynamic(R::class.java, arg0, arg1, arg2, arg3, arg4) @Suppress("unused") -inline fun > CordaRPCOps.startTrackedFlow( +inline fun > CordaRPCOps.startTrackedFlow( @Suppress("unused_parameter") flowConstructor: (A, B, C, D, E, F) -> R, arg0: A, diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index d4f51ee21f..0e76592081 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -127,7 +127,7 @@ class CordaRPCOpsImpl( } } - override fun startTrackedFlowDynamic(logicType: Class>, vararg args: Any?): FlowProgressHandle { + override fun startTrackedFlowDynamic(logicType: Class>, vararg args: Any?): FlowProgressHandle { val stateMachine = startFlow(logicType, args) return FlowProgressHandleImpl( id = stateMachine.id, @@ -136,12 +136,12 @@ class CordaRPCOpsImpl( ) } - override fun startFlowDynamic(logicType: Class>, vararg args: Any?): FlowHandle { + override fun startFlowDynamic(logicType: Class>, vararg args: Any?): FlowHandle { val stateMachine = startFlow(logicType, args) return FlowHandleImpl(id = stateMachine.id, returnValue = stateMachine.resultFuture) } - private fun startFlow(logicType: Class>, args: Array): FlowStateMachineImpl { + private fun startFlow(logicType: Class>, args: Array): FlowStateMachineImpl { require(logicType.isAnnotationPresent(StartableByRPC::class.java)) { "${logicType.name} was not designed for RPC" } val rpcContext = getRpcContext() rpcContext.requirePermission(startFlowPermission(logicType)) diff --git a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt index 260e930ce8..5aee5ca7b9 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt @@ -126,7 +126,7 @@ interface ServiceHubInternal : PluginServiceHub { * @throws net.corda.core.flows.IllegalFlowLogicException or IllegalArgumentException if there are problems with the * [logicType] or [args]. */ - fun invokeFlowAsync( + fun invokeFlowAsync( logicType: Class>, flowInitiator: FlowInitiator, vararg args: Any?): FlowStateMachineImpl { diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index 158a8ce8b3..d252d5a048 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -7,6 +7,7 @@ import net.corda.core.contracts.Issued import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.keys import net.corda.core.flows.FlowLogic +import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StateMachineRunId import net.corda.core.messaging.* import net.corda.core.node.services.ServiceInfo @@ -44,6 +45,7 @@ import rx.Observable import java.io.ByteArrayOutputStream import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNull import kotlin.test.assertTrue class CordaRPCOpsImplTest { @@ -71,12 +73,6 @@ class CordaRPCOpsImplTest { startFlowPermission(), startFlowPermission() )))) - - aliceNode.database.transaction { - stateMachineUpdates = rpc.stateMachinesFeed().updates - transactions = rpc.verifiedTransactionsFeed().updates - vaultTrackCash = rpc.vaultTrackBy().updates - } } @After @@ -86,6 +82,11 @@ class CordaRPCOpsImplTest { @Test fun `cash issue accepted`() { + aliceNode.database.transaction { + stateMachineUpdates = rpc.stateMachinesFeed().updates + vaultTrackCash = rpc.vaultTrackBy().updates + } + val quantity = 1000L val ref = OpaqueBytes(ByteArray(1) { 1 }) @@ -131,6 +132,12 @@ class CordaRPCOpsImplTest { @Test fun `issue and move`() { + aliceNode.database.transaction { + stateMachineUpdates = rpc.stateMachinesFeed().updates + transactions = rpc.verifiedTransactionsFeed().updates + vaultTrackCash = rpc.vaultTrackBy().updates + } + val anonymous = false val result = rpc.startFlow(::CashIssueFlow, 100.DOLLARS, @@ -248,4 +255,20 @@ class CordaRPCOpsImplTest { @Suspendable override fun call() = Unit } + + @Test + fun `attempt to start RPC flow with void return`() { + CURRENT_RPC_CONTEXT.set(RpcContext(User("user", "pwd", permissions = setOf( + startFlowPermission() + )))) + val result = rpc.startFlow(::VoidRPCFlow) + mockNet.runNetwork() + assertNull(result.returnValue.getOrThrow()) + } + + @StartableByRPC + class VoidRPCFlow : FlowLogic() { + @Suspendable + override fun call() : Void? = null + } }