From 99219c6a5fc4473ad5a9a104985a8ddcea1fcc9f Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Mon, 5 Dec 2016 16:22:45 +0000 Subject: [PATCH 1/2] Allow cordapp types to be used in parameters to cordapp startFlowDynamic RPC calls. Add missing registration. --- .../main/kotlin/net/corda/client/impl/CordaRPCClientImpl.kt | 2 +- .../net/corda/node/services/messaging/RPCDispatcher.kt | 4 ++-- .../net/corda/node/services/messaging/RPCStructures.kt | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/client/src/main/kotlin/net/corda/client/impl/CordaRPCClientImpl.kt b/client/src/main/kotlin/net/corda/client/impl/CordaRPCClientImpl.kt index 3487e281b2..dec85330fc 100644 --- a/client/src/main/kotlin/net/corda/client/impl/CordaRPCClientImpl.kt +++ b/client/src/main/kotlin/net/corda/client/impl/CordaRPCClientImpl.kt @@ -219,7 +219,7 @@ class CordaRPCClientImpl(private val session: ClientSession, val msg: ClientMessage = createMessage(method) val kryo = if (returnsObservables) maybePrepareForObservables(location, method, msg) else null val serializedArgs = try { - (args ?: emptyArray()).serialize() + (args ?: emptyArray()).serialize(createRPCKryo()) } catch (e: KryoException) { throw RPCException("Could not serialize RPC arguments", e) } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCDispatcher.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCDispatcher.kt index dbbd4a9b01..36abd15042 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCDispatcher.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCDispatcher.kt @@ -70,13 +70,14 @@ abstract class RPCDispatcher(val ops: RPCOps, val userService: RPCUserService) { fun dispatch(msg: ClientRPCRequestMessage) { val (argsBytes, replyTo, observationsTo, methodName) = msg + val kryo = createRPCKryo(observableSerializer = if (observationsTo != null) ObservableSerializer(observationsTo) else null) val response: ErrorOr = ErrorOr.catch { val method = methodTable[methodName] ?: throw RPCException("Received RPC for unknown method $methodName - possible client/server version skew?") if (method.isAnnotationPresent(RPCReturnsObservables::class.java) && observationsTo == null) throw RPCException("Received RPC without any destination for observations, but the RPC returns observables") - val args = argsBytes.deserialize() + val args = argsBytes.deserialize(kryo) rpcLog.debug { "-> RPC -> $methodName(${args.joinToString()}) [reply to $replyTo]" } @@ -88,7 +89,6 @@ abstract class RPCDispatcher(val ops: RPCOps, val userService: RPCUserService) { } rpcLog.debug { "<- RPC <- $methodName = $response " } - val kryo = createRPCKryo(observableSerializer = if (observationsTo != null) ObservableSerializer(observationsTo) else null) // Serialise, or send back a simple serialised ErrorOr structure if we couldn't do it. val responseBits = try { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt index e334dd6816..542696ffa3 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt @@ -132,6 +132,8 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(WireTransaction::class.java, WireTransactionSerializer) register(SerializedBytes::class.java, SerializedBytesSerializer) register(Party::class.java) + register(Array(0,{}).javaClass) + register(Class::class.java) ImmutableListSerializer.registerSerializers(this) ImmutableSetSerializer.registerSerializers(this) @@ -165,6 +167,7 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(StateMachineRunId::class.java) register(StateMachineTransactionMapping::class.java) register(UUID::class.java) + register(UniqueIdentifier::class.java) register(LinkedHashSet::class.java) register(StateAndRef::class.java) register(setOf().javaClass) // EmptySet @@ -210,6 +213,8 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(ServiceEntry::class.java) // Exceptions. We don't bother sending the stack traces as the client will fill in its own anyway. register(IllegalArgumentException::class.java) + register(ArrayIndexOutOfBoundsException::class.java) + register(IndexOutOfBoundsException::class.java) // Kryo couldn't serialize Collections.unmodifiableCollection in Throwable correctly, causing null pointer exception when try to access the deserialize object. register(NoSuchElementException::class.java, JavaSerializer()) register(RPCException::class.java) From fd229df956502ba5d725d3ba7be0737db894815d Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Tue, 6 Dec 2016 13:52:15 +0000 Subject: [PATCH 2/2] node: Add ClassSerializer, register default flow parameters for RPC --- .../net/corda/node/internal/AbstractNode.kt | 16 ++++++++-------- .../node/services/messaging/RPCStructures.kt | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 34cd6bd068..ad4e7c7acb 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -76,6 +76,14 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo companion object { val PRIVATE_KEY_FILE_NAME = "identity-private-key" val PUBLIC_IDENTITY_FILE_NAME = "identity-public" + + val defaultFlowWhiteList: Map>, Set>> = mapOf( + CashFlow::class.java to setOf( + CashCommand.IssueCash::class.java, + CashCommand.PayCash::class.java, + CashCommand.ExitCash::class.java + ) + ) } // TODO: Persist this, as well as whether the node is registered. @@ -309,14 +317,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo } } - private val defaultFlowWhiteList: Map>, Set>> = mapOf( - CashFlow::class.java to setOf( - CashCommand.IssueCash::class.java, - CashCommand.PayCash::class.java, - CashCommand.ExitCash::class.java - ) - ) - private fun initialiseFlowLogicFactory(): FlowLogicRefFactory { val flowWhitelist = HashMap>() diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt index 542696ffa3..bbe9285964 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCStructures.kt @@ -26,6 +26,7 @@ import net.corda.core.serialization.* import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction import net.corda.flows.CashFlowResult +import net.corda.node.internal.AbstractNode import net.corda.node.services.User import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPublicKey @@ -106,6 +107,17 @@ open class RPCException(msg: String, cause: Throwable?) : RuntimeException(msg, class DeadlineExceeded(rpcName: String) : RPCException("Deadline exceeded on call to $rpcName") } +object ClassSerializer : Serializer>() { + override fun read(kryo: Kryo, input: Input, type: Class>): Class<*> { + val className = input.readString() + return Class.forName(className) + } + + override fun write(kryo: Kryo, output: Output, clazz: Class<*>) { + output.writeString(clazz.name) + } +} + class PermissionException(msg: String) : RuntimeException(msg) // The Kryo used for the RPC wire protocol. Every type in the wire protocol is listed here explicitly. @@ -133,7 +145,7 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(SerializedBytes::class.java, SerializedBytesSerializer) register(Party::class.java) register(Array(0,{}).javaClass) - register(Class::class.java) + register(Class::class.java, ClassSerializer) ImmutableListSerializer.registerSerializers(this) ImmutableSetSerializer.registerSerializers(this) @@ -224,6 +236,11 @@ private class RPCKryo(observableSerializer: Serializer>? = null) register(FlowHandle::class.java) register(KryoException::class.java) register(StringBuffer::class.java) + for ((_flow, argumentTypes) in AbstractNode.defaultFlowWhiteList) { + for (type in argumentTypes) { + register(type) + } + } pluginRegistries.forEach { it.registerRPCKryoTypes(this) } }