diff --git a/.ci/dev/integration/Jenkinsfile b/.ci/dev/integration/Jenkinsfile index 55632617de..420ad78d2a 100644 --- a/.ci/dev/integration/Jenkinsfile +++ b/.ci/dev/integration/Jenkinsfile @@ -6,7 +6,10 @@ killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) pipeline { agent { label 'local-k8s' } - options { timestamps() } + options { + timestamps() + timeout(time: 3, unit: 'HOURS') + } environment { DOCKER_TAG_TO_USE = "${UUID.randomUUID().toString().toLowerCase().subSequence(0, 12)}" diff --git a/.ci/dev/nightly-regression/Jenkinsfile b/.ci/dev/nightly-regression/Jenkinsfile index 97c9ad5f7a..de26a41c90 100644 --- a/.ci/dev/nightly-regression/Jenkinsfile +++ b/.ci/dev/nightly-regression/Jenkinsfile @@ -9,6 +9,7 @@ pipeline { timestamps() overrideIndexTriggers(false) buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7')) + timeout(time: 3, unit: 'HOURS') } triggers { pollSCM ignorePostCommitHooks: true, scmpoll_spec: '@midnight' diff --git a/.ci/dev/regression/Jenkinsfile b/.ci/dev/regression/Jenkinsfile index 4ee366f70b..ed550bd401 100644 --- a/.ci/dev/regression/Jenkinsfile +++ b/.ci/dev/regression/Jenkinsfile @@ -8,6 +8,7 @@ pipeline { options { timestamps() buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7')) + timeout(time: 3, unit: 'HOURS') } environment { diff --git a/.ci/dev/smoke/Jenkinsfile b/.ci/dev/smoke/Jenkinsfile index cba97312af..05aec41e59 100644 --- a/.ci/dev/smoke/Jenkinsfile +++ b/.ci/dev/smoke/Jenkinsfile @@ -5,8 +5,11 @@ killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) pipeline { agent { label 'local-k8s' } - options { timestamps() - overrideIndexTriggers(false) } + options { + timestamps() + overrideIndexTriggers(false) + timeout(time: 3, unit: 'HOURS') + } triggers { issueCommentTrigger('.*smoke tests.*') diff --git a/.ci/dev/unit/Jenkinsfile b/.ci/dev/unit/Jenkinsfile index dd2176ea4e..0b7facd77c 100644 --- a/.ci/dev/unit/Jenkinsfile +++ b/.ci/dev/unit/Jenkinsfile @@ -6,7 +6,10 @@ killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) pipeline { agent { label 'local-k8s' } - options { timestamps() } + options { + timestamps() + timeout(time: 3, unit: 'HOURS') + } environment { DOCKER_TAG_TO_USE = "${UUID.randomUUID().toString().toLowerCase().subSequence(0, 12)}" diff --git a/Jenkinsfile b/Jenkinsfile index f7ea019654..fa039b4fdc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,7 +6,10 @@ killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger()) pipeline { agent { label 'local-k8s' } - options { timestamps() } + options { + timestamps() + timeout(time: 3, unit: 'HOURS') + } environment { DOCKER_TAG_TO_USE = "${env.GIT_COMMIT.subSequence(0, 8)}" diff --git a/core-tests/src/test/kotlin/net/corda/coretests/crypto/X509NameConstraintsTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/crypto/X509NameConstraintsTest.kt index 46a941f3f9..98f5e74a18 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/crypto/X509NameConstraintsTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/crypto/X509NameConstraintsTest.kt @@ -12,6 +12,7 @@ import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.NameConstraints import org.bouncycastle.jce.provider.BouncyCastleProvider import org.junit.Test +import java.security.Security import java.security.UnrecoverableKeyException import java.security.cert.CertPathValidator import java.security.cert.CertPathValidatorException @@ -93,7 +94,8 @@ class X509NameConstraintsTest { } @Test(timeout=300_000) - fun `x500 name with correct cn and extra attribute`() { + fun `x500 name with correct cn and extra attribute`() { + Security.addProvider(BouncyCastleProvider()) val acceptableNames = listOf("CN=Bank A TLS, UID=", "O=Bank A") .map { GeneralSubtree(GeneralName(X500Name(it))) }.toTypedArray() diff --git a/docs/source/corda-configuration-file.rst b/docs/source/corda-configuration-file.rst index ce4ea72763..bfe4c781ce 100644 --- a/docs/source/corda-configuration-file.rst +++ b/docs/source/corda-configuration-file.rst @@ -452,6 +452,13 @@ notary *Default:* not defined + etaMessageThresholdSeconds + If the wait time estimate on the internal queue exceeds this value, the notary may send + a wait time update to the client (implementation specific and dependent on the counter + party version). + + *Default:* Implementation dependent + raft *(Experimental)* If part of a distributed Raft cluster, specify this configuration object with the following settings: diff --git a/node/src/integration-test-slow/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt b/node/src/integration-test-slow/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt index 9a6c22ab20..55dcbcfc9f 100644 --- a/node/src/integration-test-slow/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt +++ b/node/src/integration-test-slow/kotlin/net/corda/node/services/distributed/DistributedServiceTests.kt @@ -25,6 +25,7 @@ import net.corda.testing.node.internal.DummyClusterSpec import net.corda.testing.node.internal.FINANCE_CORDAPPS import net.corda.testing.node.internal.cordappWithPackages import org.assertj.core.api.Assertions.assertThat +import org.junit.Ignore import org.junit.Test import rx.Observable import java.util.* @@ -81,6 +82,7 @@ class DistributedServiceTests { } // TODO This should be in RaftNotaryServiceTests + @Ignore @Test(timeout=300_000) fun `cluster survives if a notary is killed`() { setup { @@ -119,6 +121,7 @@ class DistributedServiceTests { // TODO Use a dummy distributed service rather than a Raft Notary Service as this test is only about Artemis' ability // to handle distributed services + @Ignore @Test(timeout=300_000) fun `requests are distributed evenly amongst the nodes`() { setup { diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index b01d42ae6d..417012ba3e 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -86,7 +86,7 @@ open class NetworkRegistrationHelper( * @throws CertificateRequestException if the certificate retrieved by doorman is invalid. */ fun generateKeysAndRegister() { - certificatesDirectory.createDirectories() + certificatesDirectory.safeSymbolicRead().createDirectories() // We need this in case cryptoService and certificateStore share the same KeyStore (for backwards compatibility purposes). // If we didn't, then an update to cryptoService wouldn't be reflected to certificateStore that is already loaded in memory. val certStore: CertificateStore = if (cryptoService is BCCryptoService) cryptoService.certificateStore else certificateStore diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt index a2d9362783..caeacc5b71 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt @@ -12,6 +12,7 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.internal.CertRole import net.corda.core.internal.createDirectories import net.corda.core.internal.div +import net.corda.core.internal.safeSymbolicRead import net.corda.core.internal.toX500Name import net.corda.core.utilities.seconds import net.corda.node.NodeRegistrationOption @@ -36,6 +37,7 @@ import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest import org.junit.After import org.junit.Before import org.junit.Test +import java.nio.file.Files import java.security.PublicKey import java.security.cert.CertPathValidatorException import java.security.cert.X509Certificate @@ -204,6 +206,20 @@ class NetworkRegistrationHelperTest { } } + @Test(timeout=300_000) + fun `successful registration with symbolic link for certificates directory`() { + assertThat(config.signingCertificateStore.getOptional()).isNull() + assertThat(config.p2pSslOptions.keyStore.getOptional()).isNull() + assertThat(config.p2pSslOptions.trustStore.getOptional()).isNull() + + val originalCertificatesDirectory = (config.baseDirectory / "certificates2").createDirectories() + Files.createSymbolicLink(config.certificatesDirectory, originalCertificatesDirectory) + + val rootAndIntermediateCA = createDevIntermediateCaCertPath().also { saveNetworkTrustStore(CORDA_ROOT_CA to it.first.certificate) } + + createRegistrationHelper(rootAndIntermediateCA = rootAndIntermediateCA).generateKeysAndRegister() + } + private fun createNodeCaCertPath(type: CertificateType = CertificateType.NODE_CA, legalName: CordaX500Name = nodeLegalName, publicKey: PublicKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public, @@ -268,7 +284,7 @@ class NetworkRegistrationHelperTest { * the certificate itself. */ private fun saveNetworkTrustStore(vararg trustedCertificates: Pair) { - config.certificatesDirectory.createDirectories() + config.certificatesDirectory.safeSymbolicRead().createDirectories() val rootTruststorePath = config.certificatesDirectory / networkRootTrustStoreFileName X509KeyStore.fromFile(rootTruststorePath, networkRootTrustStorePassword, createNew = true).update { trustedCertificates.forEach { diff --git a/tools/shell/src/main/java/net/corda/tools/shell/HashLookupShellCommand.java b/tools/shell/src/main/java/net/corda/tools/shell/HashLookupShellCommand.java index 3024d8015a..53b7c147d4 100644 --- a/tools/shell/src/main/java/net/corda/tools/shell/HashLookupShellCommand.java +++ b/tools/shell/src/main/java/net/corda/tools/shell/HashLookupShellCommand.java @@ -22,13 +22,13 @@ public class HashLookupShellCommand extends InteractiveShellCommand { @Man("Checks if a transaction matching a specified Id hash value is recorded on this node.\n\n" + "This is mainly intended to be used for troubleshooting notarisation issues when a\n" + "state is claimed to be already consumed by another transaction.\n\n" + - "Example usage: hash-lookup E470FD8A6350A74217B0A99EA5FB71F091C84C64AD0DE0E72ECC10421D03AAC9" + "Example usage: hashLookup E470FD8A6350A74217B0A99EA5FB71F091C84C64AD0DE0E72ECC10421D03AAC9" ) public void main(@Usage("A hexadecimal SHA-256 hash value representing the hashed transaction Id") @Argument(unquote = false) String txIdHash) { - logger.info("Executing command \"hash-lookup\"."); + logger.info("Executing command \"hashLookup\"."); if (txIdHash == null) { - out.println("Please provide a hexadecimal transaction Id hash value, see 'man hash-lookup'", Decoration.bold, Color.red); + out.println("Please provide a hexadecimal transaction Id hash value, see 'man hashLookup'", Decoration.bold, Color.red); return; }