diff --git a/.ci/api-current.txt b/.ci/api-current.txt index 230c486b46..91a2c644df 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -4356,7 +4356,7 @@ public static final class net.corda.client.rpc.CordaRPCClientConfiguration$Compa public int getServerProtocolVersion() public void notifyServerAndClose() ## -public final class net.corda.client.rpc.PermissionException extends net.corda.core.CordaRuntimeException implements net.corda.nodeapi.exceptions.RpcSerializableError +public final class net.corda.client.rpc.PermissionException extends net.corda.core.CordaRuntimeException public (String) ## @net.corda.core.DoNotImplement public interface net.corda.client.rpc.RPCConnection extends java.io.Closeable diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt index f31c2d6a49..b95480b95b 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt @@ -12,6 +12,7 @@ import net.corda.finance.DOLLARS import net.corda.finance.USD import net.corda.finance.contracts.getCashBalance import net.corda.finance.contracts.getCashBalances +import net.corda.finance.flows.CashException import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.schemas.CashSchemaV1 @@ -19,7 +20,6 @@ import net.corda.node.internal.Node import net.corda.node.internal.StartedNode import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.exceptions.InternalNodeException import net.corda.testing.core.* import net.corda.testing.node.User import net.corda.testing.node.internal.NodeBasedTest @@ -101,7 +101,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C fun `sub-type of FlowException thrown by flow`() { login(rpcUser.username, rpcUser.password) val handle = connection!!.proxy.startFlow(::CashPaymentFlow, 100.DOLLARS, identity) - assertThatExceptionOfType(InternalNodeException::class.java).isThrownBy { + assertThatExceptionOfType(CashException::class.java).isThrownBy { handle.returnValue.getOrThrow() } } diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/PermissionException.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/PermissionException.kt index a11dcdeb11..71596c6e5e 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/PermissionException.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/PermissionException.kt @@ -2,10 +2,9 @@ package net.corda.client.rpc import net.corda.core.CordaRuntimeException import net.corda.core.serialization.CordaSerializable -import net.corda.nodeapi.exceptions.RpcSerializableError /** * Thrown to indicate that the calling user does not have permission for something they have requested (for example * calling a method). */ -class PermissionException(message: String) : CordaRuntimeException(message), RpcSerializableError +class PermissionException(msg: String) : CordaRuntimeException(msg) diff --git a/core/src/main/kotlin/net/corda/core/Utils.kt b/core/src/main/kotlin/net/corda/core/Utils.kt index d2d15b87aa..d9702f53aa 100644 --- a/core/src/main/kotlin/net/corda/core/Utils.kt +++ b/core/src/main/kotlin/net/corda/core/Utils.kt @@ -5,7 +5,6 @@ package net.corda.core import net.corda.core.concurrent.CordaFuture import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.concurrent.thenMatch -import net.corda.core.messaging.DataFeed import rx.Observable import rx.Observer @@ -45,29 +44,3 @@ fun Observable.toFuture(): CordaFuture = openFuture().also { } } } - -/** - * Returns a [DataFeed] that transforms errors according to the provided [transform] function. - */ -fun DataFeed.mapErrors(transform: (Throwable) -> Throwable): DataFeed { - - return copy(updates = updates.mapErrors(transform)) -} - -/** - * Returns a [DataFeed] that processes errors according to the provided [action]. - */ -fun DataFeed.doOnError(action: (Throwable) -> Unit): DataFeed { - - return copy(updates = updates.doOnError(action)) -} - -/** - * Returns an [Observable] that transforms errors according to the provided [transform] function. - */ -fun Observable.mapErrors(transform: (Throwable) -> Throwable): Observable { - - return onErrorResumeNext { error -> - Observable.error(transform(error)) - } -} diff --git a/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt b/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt index c51deac096..6ff8ce4f2c 100644 --- a/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt +++ b/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt @@ -39,29 +39,6 @@ fun CordaFuture.map(transform: (V) -> W): CordaFuture = CordaFu }) } -/** - * Returns a future that will also apply the passed closure on an error. - */ -fun CordaFuture.doOnError(accept: (Throwable) -> Unit): CordaFuture = CordaFutureImpl().also { result -> - thenMatch({ - result.capture { it } - }, { - accept(it) - result.setException(it) - }) -} - -/** - * Returns a future that will map an error thrown using the provided [transform] function. - */ -fun CordaFuture.mapError(transform: (Throwable) -> Throwable): CordaFuture = CordaFutureImpl().also { result -> - thenMatch({ - result.capture { it } - }, { - result.setException(transform(it)) - }) -} - /** * Returns a future that will have the same outcome as the future returned by the given transform. * But if this future or the transform fails, the returned future's outcome is the same throwable. diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index ca7cbb2293..f4d0dcd113 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -7,8 +7,6 @@ from the previous milestone release. Unreleased ---------- -* Errors thrown by a Corda node will now reported to a calling RPC client with attention to serialization and obfuscation of internal data. - * Update the fast-classpath-scanner dependent library version from 2.0.21 to 2.12.3 .. note:: Whilst this is not the latest version of this library, that being 2.18.1 at time of writing, versions later diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/InternalNodeException.kt b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/InternalNodeException.kt deleted file mode 100644 index 805841ee7c..0000000000 --- a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/InternalNodeException.kt +++ /dev/null @@ -1,32 +0,0 @@ -package net.corda.nodeapi.exceptions - -import net.corda.core.CordaRuntimeException -import java.io.InvalidClassException - -// could change to use package name matching but trying to avoid reflection for now -private val whitelisted = setOf( - InvalidClassException::class, - RpcSerializableError::class -) - -/** - * An [Exception] to signal RPC clients that something went wrong within a Corda node. - */ -class InternalNodeException(message: String) : CordaRuntimeException(message) { - - companion object { - - private const val DEFAULT_MESSAGE = "Something went wrong within the Corda node." - - fun defaultMessage(): String = DEFAULT_MESSAGE - - fun obfuscateIfInternal(wrapped: Throwable): Throwable { - - (wrapped as? CordaRuntimeException)?.setCause(null) - return when { - whitelisted.any { it.isInstance(wrapped) } -> wrapped - else -> InternalNodeException(DEFAULT_MESSAGE) - } - } - } -} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/OutdatedNetworkParameterHashException.kt b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/OutdatedNetworkParameterHashException.kt deleted file mode 100644 index 8c21c2b943..0000000000 --- a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/OutdatedNetworkParameterHashException.kt +++ /dev/null @@ -1,11 +0,0 @@ -package net.corda.nodeapi.exceptions - -import net.corda.core.CordaRuntimeException -import net.corda.core.crypto.SecureHash - -class OutdatedNetworkParameterHashException(old: SecureHash, new: SecureHash) : CordaRuntimeException(TEMPLATE.format(old, new)), RpcSerializableError { - - private companion object { - private const val TEMPLATE = "Refused to accept parameters with hash %s because network map advertises update with hash %s. Please check newest version" - } -} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RejectedCommandException.kt b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RejectedCommandException.kt index 024535d274..8fd3004046 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RejectedCommandException.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RejectedCommandException.kt @@ -5,4 +5,4 @@ import net.corda.core.CordaRuntimeException /** * Thrown to indicate that the command was rejected by the node, typically due to a special temporary mode. */ -class RejectedCommandException(message: String) : CordaRuntimeException(message), RpcSerializableError \ No newline at end of file +class RejectedCommandException(msg: String) : CordaRuntimeException(msg) \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RpcSerializableError.kt b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RpcSerializableError.kt deleted file mode 100644 index 8756f0f72f..0000000000 --- a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/RpcSerializableError.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.corda.nodeapi.exceptions - -import net.corda.core.serialization.CordaSerializable - -/** - * Allows an implementing [Throwable] to be propagated to RPC clients. - */ -@CordaSerializable -interface RpcSerializableError \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/adapters/InternalObfuscatingFlowHandle.kt b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/adapters/InternalObfuscatingFlowHandle.kt deleted file mode 100644 index fbef080c7a..0000000000 --- a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/adapters/InternalObfuscatingFlowHandle.kt +++ /dev/null @@ -1,15 +0,0 @@ -package net.corda.nodeapi.exceptions.adapters - -import net.corda.core.internal.concurrent.mapError -import net.corda.core.messaging.FlowHandle -import net.corda.core.serialization.CordaSerializable -import net.corda.nodeapi.exceptions.InternalNodeException - -/** - * Adapter able to mask errors within a Corda node for RPC clients. - */ -@CordaSerializable -data class InternalObfuscatingFlowHandle(val wrapped: FlowHandle) : FlowHandle by wrapped { - - override val returnValue = wrapped.returnValue.mapError(InternalNodeException.Companion::obfuscateIfInternal) -} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/adapters/InternalObfuscatingFlowProgressHandle.kt b/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/adapters/InternalObfuscatingFlowProgressHandle.kt deleted file mode 100644 index 7b8f13f3cb..0000000000 --- a/node-api/src/main/kotlin/net/corda/nodeapi/exceptions/adapters/InternalObfuscatingFlowProgressHandle.kt +++ /dev/null @@ -1,22 +0,0 @@ -package net.corda.nodeapi.exceptions.adapters - -import net.corda.core.internal.concurrent.mapError -import net.corda.core.mapErrors -import net.corda.core.messaging.FlowProgressHandle -import net.corda.core.serialization.CordaSerializable -import net.corda.nodeapi.exceptions.InternalNodeException - -/** - * Adapter able to mask errors within a Corda node for RPC clients. - */ -@CordaSerializable -class InternalObfuscatingFlowProgressHandle(val wrapped: FlowProgressHandle) : FlowProgressHandle by wrapped { - - override val returnValue = wrapped.returnValue.mapError(InternalNodeException.Companion::obfuscateIfInternal) - - override val progress = wrapped.progress.mapErrors(InternalNodeException.Companion::obfuscateIfInternal) - - override val stepsTreeIndexFeed = wrapped.stepsTreeIndexFeed?.mapErrors(InternalNodeException.Companion::obfuscateIfInternal) - - override val stepsTreeFeed = wrapped.stepsTreeFeed?.mapErrors(InternalNodeException.Companion::obfuscateIfInternal) -} \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/ClientRelevantException.kt b/node/src/integration-test/kotlin/net/corda/ClientRelevantException.kt deleted file mode 100644 index 614cbae99f..0000000000 --- a/node/src/integration-test/kotlin/net/corda/ClientRelevantException.kt +++ /dev/null @@ -1,6 +0,0 @@ -package net.corda - -import net.corda.core.CordaRuntimeException -import net.corda.nodeapi.exceptions.RpcSerializableError - -class ClientRelevantException(message: String?, cause: Throwable?) : CordaRuntimeException(message, cause), RpcSerializableError \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt index c1dc97f3f4..75d2418592 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt @@ -5,6 +5,7 @@ import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.* import net.corda.core.cordapp.CordappProvider import net.corda.core.flows.FlowLogic +import net.corda.core.flows.UnexpectedFlowEndException import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.concurrent.transpose @@ -21,7 +22,6 @@ import net.corda.core.utilities.contextLogger import net.corda.core.utilities.getOrThrow import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl -import net.corda.nodeapi.exceptions.InternalNodeException import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME @@ -113,7 +113,7 @@ class AttachmentLoadingTests { driver { installIsolatedCordappTo(bankAName) val (bankA, bankB) = createTwoNodes() - assertFailsWith { + assertFailsWith("Party C=CH,L=Zurich,O=BankB rejected session request: Don't know net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Initiator") { bankA.rpc.startFlowDynamic(flowInitiatorClass, bankB.nodeInfo.legalIdentities.first()).returnValue.getOrThrow() } } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt deleted file mode 100644 index ad3b08daaa..0000000000 --- a/node/src/integration-test/kotlin/net/corda/node/services/rpc/RpcExceptionHandlingTest.kt +++ /dev/null @@ -1,120 +0,0 @@ -package net.corda.node.services.rpc - -import co.paralleluniverse.fibers.Suspendable -import net.corda.ClientRelevantException -import net.corda.core.flows.* -import net.corda.core.identity.Party -import net.corda.core.messaging.startFlow -import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.unwrap -import net.corda.node.services.Permissions -import net.corda.nodeapi.exceptions.InternalNodeException -import net.corda.testing.core.singleIdentity -import net.corda.testing.driver.DriverParameters -import net.corda.testing.driver.NodeParameters -import net.corda.testing.driver.driver -import net.corda.testing.node.User -import org.assertj.core.api.Assertions.assertThatCode -import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat -import org.hibernate.exception.GenericJDBCException -import org.junit.Test -import java.sql.SQLException - -class RpcExceptionHandlingTest { - - private val user = User("mark", "dadada", setOf(Permissions.all())) - private val users = listOf(user) - - @Test - fun `rpc client handles exceptions thrown on node side`() { - - driver(DriverParameters(startNodesInProcess = true)) { - - val node = startNode(NodeParameters(rpcUsers = users)).getOrThrow() - - assertThatCode { node.rpc.startFlow(::Flow).returnValue.getOrThrow() }.isInstanceOfSatisfying(InternalNodeException::class.java) { exception -> - - assertThat(exception).hasNoCause() - assertThat(exception.stackTrace).isEmpty() - assertThat(exception.message).isEqualTo(InternalNodeException.defaultMessage()) - } - } - } - - @Test - fun `rpc client handles client-relevant exceptions thrown on node side`() { - - driver(DriverParameters(startNodesInProcess = true)) { - - val node = startNode(NodeParameters(rpcUsers = users)).getOrThrow() - val clientRelevantMessage = "This is for the players!" - - assertThatCode { node.rpc.startFlow(::ClientRelevantErrorFlow, clientRelevantMessage).returnValue.getOrThrow() }.isInstanceOfSatisfying(ClientRelevantException::class.java) { exception -> - - assertThat(exception).hasNoCause() - assertThat(exception.stackTrace).isEmpty() - assertThat(exception.message).isEqualTo(clientRelevantMessage) - } - } - } - - @Test - fun `rpc client handles exceptions thrown on counter-party side`() { - - driver(DriverParameters(startNodesInProcess = true)) { - - val nodeA = startNode(NodeParameters(rpcUsers = users)).getOrThrow() - val nodeB = startNode(NodeParameters(rpcUsers = users)).getOrThrow() - - assertThatCode { nodeA.rpc.startFlow(::InitFlow, nodeB.nodeInfo.singleIdentity()).returnValue.getOrThrow() }.isInstanceOfSatisfying(InternalNodeException::class.java) { exception -> - - assertThat(exception).hasNoCause() - assertThat(exception.stackTrace).isEmpty() - assertThat(exception.message).isEqualTo(InternalNodeException.defaultMessage()) - } - } - } -} - -@StartableByRPC -class Flow : FlowLogic() { - - @Suspendable - override fun call(): String { - - throw GenericJDBCException("Something went wrong!", SQLException("Oops!")) - } -} - -@StartableByRPC -@InitiatingFlow -class InitFlow(private val party: Party) : FlowLogic() { - - @Suspendable - override fun call(): String { - - val session = initiateFlow(party) - return session.sendAndReceive("hey").unwrap { it } - } -} - -@InitiatedBy(InitFlow::class) -class InitiatedFlow(private val initiatingSession: FlowSession) : FlowLogic() { - - @Suspendable - override fun call() { - - initiatingSession.receive().unwrap { it } - throw GenericJDBCException("Something went wrong!", SQLException("Oops!")) - } -} - -@StartableByRPC -class ClientRelevantErrorFlow(private val message: String) : FlowLogic() { - - @Suspendable - override fun call(): String { - - throw ClientRelevantException(message, SQLException("Oops!")) - } -} \ No newline at end of file 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 93067458ed..b1d3063e4f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -203,9 +203,14 @@ internal class CordaRPCOpsImpl( } override fun queryAttachments(query: AttachmentQueryCriteria, sorting: AttachmentSort?): List { - // TODO: this operation should not require an explicit transaction - return database.transaction { - services.attachments.queryAttachments(query, sorting) + try { + return database.transaction { + services.attachments.queryAttachments(query, sorting) + } + } catch (e: Exception) { + // log and rethrow exception so we keep a copy server side + log.error(e.message) + throw e.cause ?: e } } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 9242aba047..673d7bf73a 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -295,11 +295,7 @@ open class Node(configuration: NodeConfiguration, // Start up the MQ clients. rpcMessagingClient?.run { runOnStop += this::close - when (rpcOps) { - // not sure what this RPCOps base interface is for - is SecureCordaRPCOps -> start(RpcExceptionHandlingProxy(rpcOps), securityManager) - else -> start(rpcOps, securityManager) - } + start(rpcOps, securityManager) } verifierMessagingClient?.run { runOnStop += this::stop diff --git a/node/src/main/kotlin/net/corda/node/internal/RpcExceptionHandlingProxy.kt b/node/src/main/kotlin/net/corda/node/internal/RpcExceptionHandlingProxy.kt deleted file mode 100644 index a2e50114b3..0000000000 --- a/node/src/main/kotlin/net/corda/node/internal/RpcExceptionHandlingProxy.kt +++ /dev/null @@ -1,147 +0,0 @@ -package net.corda.node.internal - -import net.corda.core.concurrent.CordaFuture -import net.corda.core.contracts.ContractState -import net.corda.core.crypto.SecureHash -import net.corda.core.doOnError -import net.corda.core.flows.FlowLogic -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.concurrent.doOnError -import net.corda.core.internal.concurrent.mapError -import net.corda.core.mapErrors -import net.corda.core.messaging.CordaRPCOps -import net.corda.core.messaging.DataFeed -import net.corda.core.messaging.FlowHandle -import net.corda.core.messaging.FlowProgressHandle -import net.corda.core.node.services.vault.* -import net.corda.core.utilities.loggerFor -import net.corda.nodeapi.exceptions.InternalNodeException -import net.corda.nodeapi.exceptions.adapters.InternalObfuscatingFlowHandle -import net.corda.nodeapi.exceptions.adapters.InternalObfuscatingFlowProgressHandle -import java.io.InputStream -import java.security.PublicKey - -class RpcExceptionHandlingProxy(private val delegate: SecureCordaRPCOps) : CordaRPCOps { - - private companion object { - private val logger = loggerFor() - } - - override val protocolVersion: Int get() = delegate.protocolVersion - - override fun startFlowDynamic(logicType: Class>, vararg args: Any?): FlowHandle = wrap { - - val handle = delegate.startFlowDynamic(logicType, *args) - val result = InternalObfuscatingFlowHandle(handle) - result.returnValue.doOnError { error -> logger.error(error.message, error) } - result - } - - override fun startTrackedFlowDynamic(logicType: Class>, vararg args: Any?): FlowProgressHandle = wrap { - - val handle = delegate.startTrackedFlowDynamic(logicType, *args) - val result = InternalObfuscatingFlowProgressHandle(handle) - result.returnValue.doOnError { error -> logger.error(error.message, error) } - result - } - - override fun waitUntilNetworkReady() = wrapFuture(delegate::waitUntilNetworkReady) - - override fun stateMachinesFeed() = wrapFeed(delegate::stateMachinesFeed) - - override fun vaultTrackBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class) = wrapFeed { delegate.vaultTrackBy(criteria, paging, sorting, contractStateType) } - - override fun vaultTrack(contractStateType: Class) = wrapFeed { delegate.vaultTrack(contractStateType) } - - override fun vaultTrackByCriteria(contractStateType: Class, criteria: QueryCriteria) = wrapFeed { delegate.vaultTrackByCriteria(contractStateType, criteria) } - - override fun vaultTrackByWithPagingSpec(contractStateType: Class, criteria: QueryCriteria, paging: PageSpecification) = wrapFeed { delegate.vaultTrackByWithPagingSpec(contractStateType, criteria, paging) } - - override fun vaultTrackByWithSorting(contractStateType: Class, criteria: QueryCriteria, sorting: Sort) = wrapFeed { delegate.vaultTrackByWithSorting(contractStateType, criteria, sorting) } - - override fun stateMachineRecordedTransactionMappingFeed() = wrapFeed(delegate::stateMachineRecordedTransactionMappingFeed) - - override fun networkMapFeed() = wrapFeed(delegate::networkMapFeed) - - override fun networkParametersFeed() = wrapFeed(delegate::networkParametersFeed) - - override fun internalVerifiedTransactionsFeed() = wrapFeed(delegate::internalVerifiedTransactionsFeed) - - override fun stateMachinesSnapshot() = wrap(delegate::stateMachinesSnapshot) - - override fun vaultQueryBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class) = wrap { delegate.vaultQueryBy(criteria, paging, sorting, contractStateType) } - - override fun vaultQuery(contractStateType: Class) = wrap { delegate.vaultQuery(contractStateType) } - - override fun vaultQueryByCriteria(criteria: QueryCriteria, contractStateType: Class) = wrap { delegate.vaultQueryByCriteria(criteria, contractStateType) } - - override fun vaultQueryByWithPagingSpec(contractStateType: Class, criteria: QueryCriteria, paging: PageSpecification) = wrap { delegate.vaultQueryByWithPagingSpec(contractStateType, criteria, paging) } - - override fun vaultQueryByWithSorting(contractStateType: Class, criteria: QueryCriteria, sorting: Sort) = wrap { delegate.vaultQueryByWithSorting(contractStateType, criteria, sorting) } - - override fun internalVerifiedTransactionsSnapshot() = wrap(delegate::internalVerifiedTransactionsSnapshot) - - override fun stateMachineRecordedTransactionMappingSnapshot() = wrap(delegate::stateMachineRecordedTransactionMappingSnapshot) - - override fun networkMapSnapshot() = wrap(delegate::networkMapSnapshot) - - override fun acceptNewNetworkParameters(parametersHash: SecureHash) = wrap { delegate.acceptNewNetworkParameters(parametersHash) } - - override fun nodeInfo() = wrap(delegate::nodeInfo) - - override fun notaryIdentities() = wrap(delegate::notaryIdentities) - - override fun addVaultTransactionNote(txnId: SecureHash, txnNote: String) = wrap { delegate.addVaultTransactionNote(txnId, txnNote) } - - override fun getVaultTransactionNotes(txnId: SecureHash) = wrap { delegate.getVaultTransactionNotes(txnId) } - - override fun attachmentExists(id: SecureHash) = wrap { delegate.attachmentExists(id) } - - override fun openAttachment(id: SecureHash) = wrap { delegate.openAttachment(id) } - - override fun uploadAttachment(jar: InputStream) = wrap { delegate.uploadAttachment(jar) } - - override fun uploadAttachmentWithMetadata(jar: InputStream, uploader: String, filename: String) = wrap { delegate.uploadAttachmentWithMetadata(jar, uploader, filename) } - - override fun queryAttachments(query: AttachmentQueryCriteria, sorting: AttachmentSort?) = wrap { delegate.queryAttachments(query, sorting) } - - override fun currentNodeTime() = wrap(delegate::currentNodeTime) - - override fun wellKnownPartyFromAnonymous(party: AbstractParty) = wrap { delegate.wellKnownPartyFromAnonymous(party) } - - override fun partyFromKey(key: PublicKey) = wrap { delegate.partyFromKey(key) } - - override fun wellKnownPartyFromX500Name(x500Name: CordaX500Name) = wrap { delegate.wellKnownPartyFromX500Name(x500Name) } - - override fun notaryPartyFromX500Name(x500Name: CordaX500Name) = wrap { delegate.notaryPartyFromX500Name(x500Name) } - - override fun partiesFromName(query: String, exactMatch: Boolean) = wrap { delegate.partiesFromName(query, exactMatch) } - - override fun registeredFlows() = wrap(delegate::registeredFlows) - - override fun nodeInfoFromParty(party: AbstractParty) = wrap { delegate.nodeInfoFromParty(party) } - - override fun clearNetworkMapCache() = wrap(delegate::clearNetworkMapCache) - - override fun setFlowsDrainingModeEnabled(enabled: Boolean) = wrap { delegate.setFlowsDrainingModeEnabled(enabled) } - - override fun isFlowsDrainingModeEnabled() = wrap(delegate::isFlowsDrainingModeEnabled) - - private fun wrap(call: () -> RESULT): RESULT { - - return try { - call.invoke() - } catch (error: Throwable) { - logger.error(error.message, error) - throw InternalNodeException.obfuscateIfInternal(error) - } - } - - private fun wrapFeed(call: () -> DataFeed) = wrap { - - call.invoke().doOnError { error -> logger.error(error.message, error) }.mapErrors(InternalNodeException.Companion::obfuscateIfInternal) - } - - private fun wrapFuture(call: () -> CordaFuture): CordaFuture = wrap { call.invoke().mapError(InternalNodeException.Companion::obfuscateIfInternal).doOnError { error -> logger.error(error.message, error) } } -} \ No newline at end of file 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 7125b0f6be..348fdec9f0 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 @@ -14,8 +14,11 @@ import net.corda.core.utilities.contextLogger import net.corda.core.utilities.minutes import net.corda.node.services.api.NetworkMapCacheInternal import net.corda.node.utilities.NamedThreadFactory -import net.corda.nodeapi.exceptions.OutdatedNetworkParameterHashException import net.corda.nodeapi.internal.network.* +import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME +import net.corda.nodeapi.internal.network.ParametersUpdate +import net.corda.nodeapi.internal.network.SignedNetworkParameters +import net.corda.nodeapi.internal.network.verifiedNetworkMapCert import rx.Subscription import rx.subjects.PublishSubject import java.nio.file.Path @@ -154,7 +157,8 @@ class NetworkMapUpdater(private val networkMapCache: NetworkMapCacheInternal, .copyTo(baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME, StandardCopyOption.REPLACE_EXISTING) networkMapClient.ackNetworkParametersUpdate(sign(parametersHash)) } else { - throw throw OutdatedNetworkParameterHashException(parametersHash, newParametersHash) + throw IllegalArgumentException("Refused to accept parameters with hash $parametersHash because network map " + + "advertises update with hash $newParametersHash. Please check newest version") } } }