From 5d3b24dcfa39334245de1387b358938a6d13a8d2 Mon Sep 17 00:00:00 2001 From: Michele Sollecito Date: Thu, 3 Jan 2019 17:59:34 +0000 Subject: [PATCH] [CORDA-2387]: Seeing warnings for "Double insert in net.corda.node.utilities.AppendOnlyPersistentMap" (fixed) (#4499) * [CORDA-2387]: Reproduced the issue in a test. * [CORDA-2387]: Fixed. * [CORDA-2387]: Fixed. --- .../node/logging/ErrorCodeLoggingTests.kt | 4 +- .../node/logging/IssueCashLoggingTests.kt | 79 +++++++++++++++++++ .../net/corda/node/logging/PackageUtils.kt | 7 ++ .../services/api/IdentityServiceInternal.kt | 2 +- 4 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 node/src/integration-test/kotlin/net/corda/node/logging/IssueCashLoggingTests.kt create mode 100644 node/src/integration-test/kotlin/net/corda/node/logging/PackageUtils.kt diff --git a/node/src/integration-test/kotlin/net/corda/node/logging/ErrorCodeLoggingTests.kt b/node/src/integration-test/kotlin/net/corda/node/logging/ErrorCodeLoggingTests.kt index a22ab7a8dc..bc3c0569a7 100644 --- a/node/src/integration-test/kotlin/net/corda/node/logging/ErrorCodeLoggingTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/logging/ErrorCodeLoggingTests.kt @@ -43,6 +43,4 @@ private fun FlowHandle<*>.waitForCompletion() { } catch (e: Exception) { // This is expected to throw an exception, using getOrThrow() just to wait until done. } -} - -private fun NodeHandle.logFile(): File = (baseDirectory / "logs").toFile().walk().filter { it.name.startsWith("node-") && it.extension == "log" }.single() \ No newline at end of file +} \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/node/logging/IssueCashLoggingTests.kt b/node/src/integration-test/kotlin/net/corda/node/logging/IssueCashLoggingTests.kt new file mode 100644 index 0000000000..64cebddfcd --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/logging/IssueCashLoggingTests.kt @@ -0,0 +1,79 @@ +package net.corda.node.logging + +import co.paralleluniverse.fibers.Suspendable +import net.corda.core.concurrent.CordaFuture +import net.corda.core.contracts.Amount +import net.corda.core.flows.StartableByRPC +import net.corda.core.identity.Party +import net.corda.core.messaging.startFlow +import net.corda.core.serialization.CordaSerializable +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.ProgressTracker +import net.corda.core.utilities.getOrThrow +import net.corda.finance.DOLLARS +import net.corda.finance.flows.AbstractCashFlow +import net.corda.finance.flows.CashIssueFlow +import net.corda.finance.flows.CashPaymentFlow +import net.corda.node.services.Permissions.Companion.all +import net.corda.testing.driver.DriverParameters +import net.corda.testing.driver.driver +import net.corda.testing.node.User +import net.corda.testing.node.internal.cordappWithPackages +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import java.util.* +import java.util.concurrent.CompletableFuture.allOf + +class IssueCashLoggingTests { + + private val UNSIGNED_FINANCE_CORDAPP = cordappWithPackages("net.corda.finance") + + @Test + fun `issuing and sending cash as payment do not result in duplicate insertion warnings`() { + val user = User("mark", "dadada", setOf(all())) + driver(DriverParameters(cordappsForAllNodes = setOf(UNSIGNED_FINANCE_CORDAPP))) { + val nodeA = startNode(rpcUsers = listOf(user)).getOrThrow() + val nodeB = startNode().getOrThrow() + + val amount = 1.DOLLARS + val ref = OpaqueBytes.of(0) + val recipient = nodeB.nodeInfo.legalIdentities[0] + + nodeA.rpc.startFlow(::CashIssueAndPaymentFlow, amount, ref, recipient, false, defaultNotaryIdentity).returnValue.getOrThrow() + + val linesWithDuplicateInsertionWarningsInA = nodeA.logFile().useLines { lines -> lines.filter(String::containsDuplicateInsertWarning).toList() } + val linesWithDuplicateInsertionWarningsInB = nodeB.logFile().useLines { lines -> lines.filter(String::containsDuplicateInsertWarning).toList() } + + assertThat(linesWithDuplicateInsertionWarningsInA).isEmpty() + assertThat(linesWithDuplicateInsertionWarningsInB).isEmpty() + } + } + + @StartableByRPC + class CashIssueAndPaymentFlow(val amount: Amount, + val issueRef: OpaqueBytes, + val recipient: Party, + val anonymous: Boolean, + val notary: Party, + progressTracker: ProgressTracker) : AbstractCashFlow(progressTracker) { + + constructor(amount: Amount, + issueRef: OpaqueBytes, + recipient: Party, + anonymous: Boolean, + notary: Party) : this(amount, issueRef, recipient, anonymous, notary, tracker()) + + constructor(request: IssueAndPaymentRequest) : this(request.amount, request.issueRef, request.recipient, request.anonymous, request.notary, tracker()) + + @Suspendable + override fun call(): Result { + subFlow(CashIssueFlow(amount, issueRef, notary)) + return subFlow(CashPaymentFlow(amount, recipient, anonymous)) + } + + @CordaSerializable + class IssueAndPaymentRequest(amount: Amount, val issueRef: OpaqueBytes, val recipient: Party, val notary: Party, val anonymous: Boolean) : AbstractRequest(amount) + } +} + +private fun String.containsDuplicateInsertWarning(): Boolean = contains("Double insert") && contains("not inserting the second time") \ No newline at end of file diff --git a/node/src/integration-test/kotlin/net/corda/node/logging/PackageUtils.kt b/node/src/integration-test/kotlin/net/corda/node/logging/PackageUtils.kt new file mode 100644 index 0000000000..cfaea5bcc7 --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/logging/PackageUtils.kt @@ -0,0 +1,7 @@ +package net.corda.node.logging + +import net.corda.core.internal.div +import net.corda.testing.driver.NodeHandle +import java.io.File + +fun NodeHandle.logFile(): File = (baseDirectory / "logs").toFile().walk().filter { it.name.startsWith("node-") && it.extension == "log" }.single() \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt index 07057b113a..070e5b0ed1 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt @@ -72,7 +72,7 @@ interface IdentityServiceInternal : IdentityService { } // Ensure we record the first identity of the same name, first val wellKnownCert = identityCertChain.single { CertRole.extract(it)?.isWellKnown ?: false } - if (wellKnownCert != identity.certificate) { + if (wellKnownCert != identity.certificate && !isNewRandomIdentity) { val idx = identityCertChain.lastIndexOf(wellKnownCert) val firstPath = X509Utilities.buildCertPath(identityCertChain.slice(idx until identityCertChain.size)) verifyAndRegisterIdentity(trustAnchor, PartyAndCertificate(firstPath))