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 6844b95ca6..f59aa49a40 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -34,13 +34,13 @@ import java.time.Instant */ @CordaSerializable data class StateMachineInfo @JvmOverloads constructor( - /** A univerally unique ID ([java.util.UUID]) representing this particular instance of the named flow. */ + /** A universally unique ID ([java.util.UUID]) representing this particular instance of the named flow. */ val id: StateMachineRunId, /** The JVM class name of the flow code. */ val flowLogicClassName: String, /** * An object representing information about the initiator of the flow. Note that this field is - * superceded by the [invocationContext] property, which has more detail. + * superseded by the [invocationContext] property, which has more detail. */ @Deprecated("There is more info available using 'context'") val initiator: FlowInitiator, /** A [DataFeed] of the current progress step as a human readable string, and updates to that string. */ @@ -368,9 +368,24 @@ interface CordaRPCOps : RPCOps { */ fun nodeInfoFromParty(party: AbstractParty): NodeInfo? - /** Clear all network map data from local node cache. */ + /** + * Clear all network map data from local node cache. Notice that after invoking this method your node will lose + * network map data and effectively won't be able to start any flow with the peers until network map is downloaded + * again on next poll - from `additional-node-infos` directory or from network map server. It depends on the + * polling interval when it happens. You can also use [refreshNetworkMapCache] to force next fetch from network map server + * (not from directory - it will happen automatically). + * If you run local test deployment and want clear view of the network, you may want to clear also `additional-node-infos` + * directory, because cache can be repopulated from there. + */ fun clearNetworkMapCache() + /** + * Poll network map server if available for the network map. Notice that you need to have `compatibilityZone` + * or `networkServices` configured. This is normally done automatically on the regular time interval, but you may wish to + * have the fresh view of network earlier. + */ + fun refreshNetworkMapCache() + /** Sets the value of the node's flows draining mode. * If this mode is [enabled], the node will reject new flows through RPC, ignore scheduled flows, and do not process * initial session messages, meaning that P2P counterparties will not be able to initiate new flows involving the node. 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 e1c9b2dd33..fcc6c7eafe 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -1,6 +1,7 @@ package net.corda.node.internal import net.corda.client.rpc.notUsed +import net.corda.core.CordaRuntimeException import net.corda.core.concurrent.CordaFuture import net.corda.core.context.InvocationContext import net.corda.core.context.InvocationOrigin @@ -48,6 +49,7 @@ import net.corda.nodeapi.exceptions.NonRpcFlowException import net.corda.nodeapi.exceptions.RejectedCommandException import rx.Observable import java.io.InputStream +import java.net.ConnectException import java.security.PublicKey import java.time.Instant @@ -232,6 +234,17 @@ internal class CordaRPCOpsImpl( services.networkMapCache.clearNetworkMapCache() } + override fun refreshNetworkMapCache() { + try { + services.networkMapUpdater.updateNetworkMapCache() + } catch (e: Exception) { + when (e) { + is ConnectException -> throw CordaRuntimeException("There is connection problem to network map. The possible causes are incorrect configuration or network map service being down") + else -> throw e + } + } + } + override fun vaultQuery(contractStateType: Class): Vault.Page { return vaultQueryBy(QueryCriteria.VaultQueryCriteria(), PageSpecification(), Sort(emptySet()), contractStateType) } diff --git a/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionSerialisingRpcOpsProxy.kt b/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionSerialisingRpcOpsProxy.kt index 7a35fa56c7..0b1e361db2 100644 --- a/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionSerialisingRpcOpsProxy.kt +++ b/node/src/main/kotlin/net/corda/node/internal/rpc/proxies/ExceptionSerialisingRpcOpsProxy.kt @@ -36,8 +36,6 @@ internal class ExceptionSerialisingRpcOpsProxy(private val delegate: CordaRPCOps val result = super.invoke(proxy, method, arguments) return result?.let { ensureSerialisable(it) } } catch (exception: Exception) { - // In this special case logging and re-throwing is the right approach. - log(exception) throw ensureSerialisable(exception) } } @@ -80,7 +78,13 @@ internal class ExceptionSerialisingRpcOpsProxy(private val delegate: CordaRPCOps private fun ensureSerialisable(error: Throwable): Throwable { val serialisable = (superclasses(error::class.java) + error::class.java).any { it.isAnnotationPresent(CordaSerializable::class.java) || it.interfaces.any { it.isAnnotationPresent(CordaSerializable::class.java) } } - val result = if (serialisable) error else CordaRuntimeException(error.message, error) + val result = if (serialisable) { + error + } else { + log(error) + CordaRuntimeException(error.message, error) + } + if (result is CordaThrowable) { result.stackTrace = arrayOf() result.setCause(null) diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt index d06abce27a..d4f1a12fc7 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt @@ -1,6 +1,7 @@ package net.corda.node.services.network import com.google.common.util.concurrent.MoreExecutors +import net.corda.core.CordaRuntimeException import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData import net.corda.core.internal.copyTo @@ -86,7 +87,7 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, executor.submit(object : Runnable { override fun run() { val nextScheduleDelay = try { - updateNetworkMapCache(networkMapClient) + updateNetworkMapCache() } catch (t: Throwable) { logger.warn("Error encountered while updating network map, will retry in $defaultRetryInterval", t) defaultRetryInterval @@ -97,7 +98,8 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, }) // The check may be expensive, so always run it in the background even the first time. } - private fun updateNetworkMapCache(networkMapClient: NetworkMapClient): Duration { + fun updateNetworkMapCache(): Duration { + if (networkMapClient == null) throw CordaRuntimeException("Network map cache can be updated only if network map/compatibility zone URL is specified") val (globalNetworkMap, cacheTimeout) = networkMapClient.getNetworkMap() globalNetworkMap.parametersUpdate?.let { handleUpdateNetworkParameters(networkMapClient, it) } val additionalHashes = extraNetworkMapKeys.flatMap {