mirror of
https://github.com/corda/corda.git
synced 2024-12-21 22:07:55 +00:00
Merge pull request #6254 from corda/adel/merge-from-4.5
Adel/merge from 4.5
This commit is contained in:
commit
ac03ba63e8
6
.ci/dev/regression/Jenkinsfile
vendored
6
.ci/dev/regression/Jenkinsfile
vendored
@ -1,13 +1,9 @@
|
||||
@Library('corda-shared-build-pipeline-steps')
|
||||
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
||||
|
||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||
|
||||
pipeline {
|
||||
agent { label 'k8s' }
|
||||
options {
|
||||
timestamps()
|
||||
buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7'))
|
||||
disableConcurrentBuilds()
|
||||
timeout(time: 3, unit: 'HOURS')
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,7 @@ buildscript {
|
||||
"unknown"
|
||||
}
|
||||
}()
|
||||
ext.corda_docs_link = "https://docs.corda.net/docs/corda-os/$baseVersion"
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
@ -309,6 +310,7 @@ allprojects {
|
||||
attributes('Corda-Revision': corda_revision)
|
||||
attributes('Corda-Vendor': 'Corda Open Source')
|
||||
attributes('Automatic-Module-Name': "net.corda.${task.project.name.replaceAll('-', '.')}")
|
||||
attributes('Corda-Docs-Link': corda_docs_link)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ class CordaVersion {
|
||||
val revision: String by lazy { manifestValue("Corda-Revision") ?: UNKNOWN }
|
||||
val vendor: String by lazy { manifestValue("Corda-Vendor") ?: UNKNOWN }
|
||||
val platformVersion: Int by lazy { manifestValue("Corda-Platform-Version")?.toInt() ?: 1 }
|
||||
val docsLink: String by lazy { manifestValue("Corda-Docs-Link") ?: UNKNOWN }
|
||||
|
||||
internal val semanticVersion: String by lazy { if(releaseVersion == UNKNOWN) CURRENT_MAJOR_RELEASE else releaseVersion }
|
||||
}
|
||||
|
@ -11,21 +11,10 @@ import java.util.*
|
||||
class CordaErrorContextProvider : ErrorContextProvider {
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "https://docs.corda.net/docs"
|
||||
private const val OS_PAGES = "corda-os"
|
||||
private const val ENTERPRISE_PAGES = "corda-enterprise"
|
||||
private const val ERROR_CODE_PAGE = "error-codes.html"
|
||||
}
|
||||
|
||||
override fun getURL(locale: Locale): String {
|
||||
val versionNumber = CordaVersion.releaseVersion
|
||||
|
||||
// This slightly strange block here allows the code to be merged across to Enterprise with no changes.
|
||||
val productVersion = if (CordaVersion.platformEditionCode == "OS") {
|
||||
OS_PAGES
|
||||
} else {
|
||||
ENTERPRISE_PAGES
|
||||
}
|
||||
return "$BASE_URL/$productVersion/$versionNumber/$ERROR_CODE_PAGE"
|
||||
return "${CordaVersion.docsLink}/$ERROR_CODE_PAGE"
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ internal class ErrorReporterImpl(private val resourceLocation: String,
|
||||
val resource = "$resourceLocation/$ERROR_INFO_RESOURCE"
|
||||
val codeMessage = fetchAndFormat(resource, ERROR_CODE_MESSAGE, arrayOf(error.formatCode()))
|
||||
val urlMessage = fetchAndFormat(resource, ERROR_CODE_URL, arrayOf(errorContextProvider.getURL(locale)))
|
||||
return "[$codeMessage, $urlMessage]"
|
||||
return "[$codeMessage $urlMessage]"
|
||||
}
|
||||
|
||||
override fun report(error: ErrorCode<*>, logger: Logger) {
|
||||
|
@ -11,7 +11,8 @@ class CordaErrorContextProviderTest {
|
||||
@Test(timeout = 300_000)
|
||||
fun `check that correct URL is returned from context provider`() {
|
||||
val context = CordaErrorContextProvider()
|
||||
val expectedURL = "https://docs.corda.net/docs/corda-os/${CordaVersion.releaseVersion}/error-codes.html"
|
||||
val version = CordaVersion.releaseVersion.substringBefore("-") // Remove SNAPSHOT if present
|
||||
val expectedURL = "https://docs.corda.net/docs/corda-os/$version/error-codes.html"
|
||||
// In this first release, there is only one localisation and the URL structure for future localisations is currently unknown. As
|
||||
// a result, the same URL is expected for all locales.
|
||||
assertEquals(expectedURL, context.getURL(Locale.getDefault()))
|
||||
|
@ -74,7 +74,7 @@ class ErrorReporterImplTest {
|
||||
val error = TEST_ERROR_1
|
||||
val testReporter = createReporterImpl("en-US")
|
||||
testReporter.report(error, loggerMock)
|
||||
assertEquals(listOf("This is a test message [Code: test-case1, URL: $TEST_URL/en-US]"), logs)
|
||||
assertEquals(listOf("This is a test message [Code: test-case1 URL: $TEST_URL/en-US]"), logs)
|
||||
}
|
||||
|
||||
@Test(timeout = 300_00)
|
||||
@ -84,7 +84,7 @@ class ErrorReporterImplTest {
|
||||
val testReporter = createReporterImpl("en-US")
|
||||
testReporter.report(error, loggerMock)
|
||||
val format = DateFormat.getDateInstance(DateFormat.LONG, Locale.forLanguageTag("en-US"))
|
||||
assertEquals(listOf("This is the second case with string foo, number 1, date ${format.format(currentDate)} [Code: test-case2, URL: $TEST_URL/en-US]"), logs)
|
||||
assertEquals(listOf("This is the second case with string foo, number 1, date ${format.format(currentDate)} [Code: test-case2 URL: $TEST_URL/en-US]"), logs)
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
@ -92,7 +92,7 @@ class ErrorReporterImplTest {
|
||||
val error = TEST_ERROR_1
|
||||
val testReporter = createReporterImpl("fr-FR")
|
||||
testReporter.report(error, loggerMock)
|
||||
assertEquals(listOf("This is a test message [Code: test-case1, URL: $TEST_URL/fr-FR]"), logs)
|
||||
assertEquals(listOf("This is a test message [Code: test-case1 URL: $TEST_URL/fr-FR]"), logs)
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
@ -100,7 +100,7 @@ class ErrorReporterImplTest {
|
||||
val error = TEST_ERROR_1
|
||||
val testReporter = createReporterImpl("ga-IE")
|
||||
testReporter.report(error, loggerMock)
|
||||
assertEquals(listOf("Is teachtaireacht earráide é seo [Code: test-case1, URL: $TEST_URL/ga-IE]"), logs)
|
||||
assertEquals(listOf("Is teachtaireacht earráide é seo [Code: test-case1 URL: $TEST_URL/ga-IE]"), logs)
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
@ -108,7 +108,7 @@ class ErrorReporterImplTest {
|
||||
val error = TEST_ERROR_1
|
||||
val testReporter = createReporterImpl("es-ES")
|
||||
testReporter.report(error, loggerMock)
|
||||
assertEquals(listOf("This is a test message [Code: test-case1, URL: $TEST_URL/es-ES]"), logs)
|
||||
assertEquals(listOf("This is a test message [Code: test-case1 URL: $TEST_URL/es-ES]"), logs)
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
@ -116,6 +116,6 @@ class ErrorReporterImplTest {
|
||||
val error = TEST_ERROR_3
|
||||
val testReporter = createReporterImpl("en-US")
|
||||
testReporter.report(error, loggerMock)
|
||||
assertEquals(listOf("This is the third test message [Code: test-case-3, URL: $TEST_URL/en-US]"), logs)
|
||||
assertEquals(listOf("This is the third test message [Code: test-case-3 URL: $TEST_URL/en-US]"), logs)
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ quasarVersion11=0.8.0_r3
|
||||
jdkClassifier11=jdk11
|
||||
proguardVersion=6.1.1
|
||||
bouncycastleVersion=1.60
|
||||
classgraphVersion=4.8.71
|
||||
classgraphVersion=4.8.78
|
||||
disruptorVersion=3.4.2
|
||||
typesafeConfigVersion=1.3.4
|
||||
jsr305Version=3.0.2
|
||||
|
@ -12,7 +12,6 @@ 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
|
||||
@ -95,7 +94,8 @@ class X509NameConstraintsTest {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `x500 name with correct cn and extra attribute`() {
|
||||
Security.addProvider(BouncyCastleProvider())
|
||||
// Do not use Security.addProvider(BouncyCastleProvider()) to avoid EdDSA signature disruption in other tests.
|
||||
Crypto.findProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||
val acceptableNames = listOf("CN=Bank A TLS, UID=", "O=Bank A")
|
||||
.map { GeneralSubtree(GeneralName(X500Name(it))) }.toTypedArray()
|
||||
|
||||
|
@ -229,8 +229,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
|
||||
"""
|
||||
State of class ${state.data ::class.java.typeName} belongs to contract $requiredContractClassName, but
|
||||
is bundled in TransactionState with ${state.contract}.
|
||||
|
||||
For details see: https://docs.corda.net/api-contract-constraints.html#contract-state-agreement
|
||||
""".trimIndent().replace('\n', ' '))
|
||||
}
|
||||
|
||||
@ -243,8 +241,6 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
|
||||
State of class ${state.data::class.java.typeName} does not have a specified owning contract.
|
||||
Add the @BelongsToContract annotation to this class to ensure that it can only be bundled in a TransactionState
|
||||
with the correct contract.
|
||||
|
||||
For details see: https://docs.corda.net/api-contract-constraints.html#contract-state-agreement
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@ -331,8 +327,7 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
|
||||
*/
|
||||
class PackageOwnershipException(txId: SecureHash, @Suppress("unused") val attachmentHash: AttachmentId, @Suppress("unused") val invalidClassName: String, val packageName: String) : TransactionVerificationException(txId,
|
||||
"""The attachment JAR: $attachmentHash containing the class: $invalidClassName is not signed by the owner of package $packageName specified in the network parameters.
|
||||
Please check the source of this attachment and if it is malicious contact your zone operator to report this incident.
|
||||
For details see: https://docs.corda.net/network-map.html#network-parameters""".trimIndent(), null)
|
||||
Please check the source of this attachment and if it is malicious contact your zone operator to report this incident.""".trimIndent(), null)
|
||||
|
||||
class InvalidAttachmentException(txId: SecureHash, @Suppress("unused") val attachmentHash: AttachmentId) : TransactionVerificationException(txId,
|
||||
"The attachment $attachmentHash is not a valid ZIP or JAR file.".trimIndent(), null)
|
||||
@ -345,8 +340,7 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
|
||||
class UntrustedAttachmentsException(val txId: SecureHash, val ids: List<SecureHash>) :
|
||||
CordaException("Attempting to load untrusted transaction attachments: $ids. " +
|
||||
"At this time these are not loadable because the DJVM sandbox has not yet been integrated. " +
|
||||
"You will need to manually install the CorDapp to whitelist it for use. " +
|
||||
"Please follow the operational steps outlined in https://docs.corda.net/cordapp-build-systems.html#cordapp-contract-attachments to learn more and continue.")
|
||||
"You will need to manually install the CorDapp to whitelist it for use.")
|
||||
|
||||
/*
|
||||
If you add a new class extending [TransactionVerificationException], please add a test in `TransactionVerificationExceptionSerializationTests`
|
||||
|
@ -52,8 +52,6 @@ object JarSignatureCollector {
|
||||
"""
|
||||
Mismatch between signers ${firstSignerSet.toOrderedPublicKeys()} for file $firstFile
|
||||
and signers ${otherSignerSet.toOrderedPublicKeys()} for file ${otherFile}.
|
||||
See https://docs.corda.net/api-contract-constraints.html#signature-constraints for details of the
|
||||
constraints applied to attachment signatures.
|
||||
""".trimIndent().replace('\n', ' '))
|
||||
}
|
||||
return firstSignerSet
|
||||
|
@ -265,8 +265,6 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
|
||||
logger.warnOnce("""
|
||||
State of class ${state.data::class.java.typeName} belongs to contract $requiredContractClassName, but
|
||||
is bundled in TransactionState with ${state.contract}.
|
||||
|
||||
For details see: https://docs.corda.net/api-contract-constraints.html#contract-state-agreement
|
||||
""".trimIndent().replace('\n', ' '))
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ object StateContractValidationEnforcementRule {
|
||||
Unable to determine JAR location for contract state class ${state::class.java.name},
|
||||
and consequently unable to determine target platform version.
|
||||
Enforcing state/contract agreement validation by default.
|
||||
|
||||
For details see: https://docs.corda.net/api-contract-constraints.html#contract-state-agreement
|
||||
""".trimIndent().replace("\n", " "))
|
||||
return true
|
||||
}
|
||||
|
@ -116,8 +116,7 @@ class AttachmentsClassLoader(attachments: List<Attachment>,
|
||||
|
||||
if (untrusted.isNotEmpty()) {
|
||||
log.warn("Cannot verify transaction $sampleTxId as the following attachment IDs are untrusted: $untrusted." +
|
||||
"You will need to manually install the CorDapp to whitelist it for use. " +
|
||||
"Please follow the operational steps outlined in https://docs.corda.net/cordapp-build-systems.html#cordapp-contract-attachments to learn more and continue.")
|
||||
"You will need to manually install the CorDapp to whitelist it for use.")
|
||||
throw TransactionVerificationException.UntrustedAttachmentsException(sampleTxId, untrusted)
|
||||
}
|
||||
|
||||
|
@ -18,5 +18,4 @@ class MissingContractAttachments
|
||||
@JvmOverloads
|
||||
constructor(val states: List<TransactionState<ContractState>>, contractsClassName: String? = null, minimumRequiredContractClassVersion: Version? = null) : FlowException(
|
||||
"Cannot find contract attachments for " +
|
||||
"${contractsClassName ?: states.map { it.contract }.distinct()}${minimumRequiredContractClassVersion?.let { ", minimum required contract class version $minimumRequiredContractClassVersion"}}. " +
|
||||
"See https://docs.corda.net/api-contract-constraints.html#debugging")
|
||||
"${contractsClassName ?: states.map { it.contract }.distinct()}${minimumRequiredContractClassVersion?.let { ", minimum required contract class version $minimumRequiredContractClassVersion"}}.")
|
||||
|
@ -265,8 +265,7 @@ class OutstandingDatabaseChangesException(@Suppress("MemberVisibilityCanBePrivat
|
||||
|
||||
class CheckpointsException : DatabaseMigrationException("Attempting to update the database while there are flows in flight. " +
|
||||
"This is dangerous because the node might not be able to restore the flows correctly and could consequently fail. " +
|
||||
"Updating the database would make reverting to the previous version more difficult. " +
|
||||
"Please drain your node first. See: https://docs.corda.net/upgrading-cordapps.html#flow-drains")
|
||||
"Updating the database would make reverting to the previous version more difficult.")
|
||||
|
||||
class DatabaseIncompatibleException(@Suppress("MemberVisibilityCanBePrivate") private val reason: String) : DatabaseMigrationException(errorMessageFor(reason)) {
|
||||
internal companion object {
|
||||
|
@ -75,7 +75,8 @@ class RpcReconnectTests {
|
||||
* This test runs flows in a loop and in the background kills the node or restarts it.
|
||||
* Also the RPC connection is made through a proxy that introduces random latencies and is also periodically killed.
|
||||
*/
|
||||
@Test(timeout=300_000)
|
||||
@Suppress("ComplexMethod")
|
||||
@Test(timeout=420_000)
|
||||
fun `test that the RPC client is able to reconnect and proceed after node failure, restart, or connection reset`() {
|
||||
val nodeRunningTime = { Random().nextInt(12000) + 8000 }
|
||||
|
||||
|
@ -58,7 +58,6 @@ import java.math.BigInteger
|
||||
import java.net.InetSocketAddress
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.Security
|
||||
import java.security.cert.X509CRL
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
@ -117,7 +116,8 @@ class CertificateRevocationListNodeTests {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
Security.addProvider(BouncyCastleProvider())
|
||||
// Do not use Security.addProvider(BouncyCastleProvider()) to avoid EdDSA signature disruption in other tests.
|
||||
Crypto.findProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||
revokedNodeCerts.clear()
|
||||
server = CrlServer(NetworkHostAndPort("localhost", 0))
|
||||
server.start()
|
||||
|
@ -32,6 +32,7 @@ import net.corda.testing.driver.driver
|
||||
import org.hibernate.exception.ConstraintViolationException
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.lang.RuntimeException
|
||||
import java.sql.Connection
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
@ -39,6 +40,7 @@ import java.util.concurrent.Semaphore
|
||||
import javax.persistence.PersistenceException
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown")
|
||||
class FlowEntityManagerTest : AbstractFlowEntityManagerTest() {
|
||||
|
||||
@Before
|
||||
@ -364,6 +366,62 @@ class FlowEntityManagerTest : AbstractFlowEntityManagerTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `non database error caught outside entity manager does not save entities`() {
|
||||
var counter = 0
|
||||
StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++counter }
|
||||
|
||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||
|
||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||
alice.rpc.startFlow(::EntityManagerSaveAndThrowNonDatabaseErrorFlow)
|
||||
.returnValue.getOrThrow(30.seconds)
|
||||
assertEquals(0, counter)
|
||||
val entities = alice.rpc.startFlow(::GetCustomEntities).returnValue.getOrThrow()
|
||||
assertEquals(0, entities.size)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `non database error caught outside entity manager after flush occurs does save entities`() {
|
||||
var counter = 0
|
||||
StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++counter }
|
||||
|
||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||
|
||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||
alice.rpc.startFlow(::EntityManagerSaveFlushAndThrowNonDatabaseErrorFlow)
|
||||
.returnValue.getOrThrow(30.seconds)
|
||||
assertEquals(0, counter)
|
||||
val entities = alice.rpc.startFlow(::GetCustomEntities).returnValue.getOrThrow()
|
||||
assertEquals(3, entities.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `database error caught inside entity manager non database exception thrown and caught outside entity manager should not save entities`() {
|
||||
var counter = 0
|
||||
StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++counter }
|
||||
|
||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||
|
||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||
alice.rpc.expectFlowSuccessAndAssertCreatedEntities(
|
||||
flow = ::EntityManagerCatchDatabaseErrorInsideEntityManagerThrowNonDatabaseErrorAndCatchOutsideFlow,
|
||||
commitStatus = CommitStatus.NO_INTERMEDIATE_COMMIT,
|
||||
numberOfDischarges = 0,
|
||||
numberOfExpectedEntities = 1
|
||||
)
|
||||
alice.rpc.expectFlowSuccessAndAssertCreatedEntities(
|
||||
flow = ::EntityManagerCatchDatabaseErrorInsideEntityManagerThrowNonDatabaseErrorAndCatchOutsideFlow,
|
||||
commitStatus = CommitStatus.INTERMEDIATE_COMMIT,
|
||||
numberOfDischarges = 0,
|
||||
numberOfExpectedEntities = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class EntityManagerSaveEntitiesWithoutAFlushFlow : FlowLogic<Unit>() {
|
||||
|
||||
@ -706,6 +764,74 @@ class FlowEntityManagerTest : AbstractFlowEntityManagerTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class EntityManagerSaveAndThrowNonDatabaseErrorFlow : FlowLogic<Unit>() {
|
||||
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
try {
|
||||
serviceHub.withEntityManager {
|
||||
persist(entityWithIdOne)
|
||||
persist(entityWithIdTwo)
|
||||
persist(entityWithIdThree)
|
||||
throw RuntimeException("die")
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
logger.info("Caught error")
|
||||
}
|
||||
sleep(1.millis)
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class EntityManagerSaveFlushAndThrowNonDatabaseErrorFlow : FlowLogic<Unit>() {
|
||||
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
try {
|
||||
serviceHub.withEntityManager {
|
||||
persist(entityWithIdOne)
|
||||
persist(entityWithIdTwo)
|
||||
persist(entityWithIdThree)
|
||||
flush()
|
||||
throw RuntimeException("die")
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
logger.info("Caught error")
|
||||
}
|
||||
sleep(1.millis)
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class EntityManagerCatchDatabaseErrorInsideEntityManagerThrowNonDatabaseErrorAndCatchOutsideFlow(private val commitStatus: CommitStatus) :
|
||||
FlowLogic<Unit>() {
|
||||
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
serviceHub.withEntityManager {
|
||||
persist(entityWithIdOne)
|
||||
}
|
||||
if (commitStatus == CommitStatus.INTERMEDIATE_COMMIT) {
|
||||
sleep(1.millis)
|
||||
}
|
||||
try {
|
||||
serviceHub.withEntityManager {
|
||||
persist(anotherEntityWithIdOne)
|
||||
try {
|
||||
flush()
|
||||
} catch (e: PersistenceException) {
|
||||
logger.info("Caught the exception!")
|
||||
}
|
||||
throw RuntimeException("die")
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
logger.info("Caught error")
|
||||
}
|
||||
sleep(1.millis)
|
||||
}
|
||||
}
|
||||
|
||||
@CordaService
|
||||
class MyService(private val services: AppServiceHub) : SingletonSerializeAsToken() {
|
||||
|
||||
|
@ -183,7 +183,7 @@ import java.sql.Savepoint
|
||||
import java.time.Clock
|
||||
import java.time.Duration
|
||||
import java.time.format.DateTimeParseException
|
||||
import java.util.*
|
||||
import java.util.Properties
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
@ -193,8 +193,6 @@ import java.util.concurrent.TimeUnit.MINUTES
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
import java.util.function.Consumer
|
||||
import javax.persistence.EntityManager
|
||||
import javax.persistence.PersistenceException
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
/**
|
||||
* A base node implementation that can be customised either for production (with real implementations that do real
|
||||
@ -912,8 +910,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
requireNotNull(getCertificateStores()) {
|
||||
"One or more keyStores (identity or TLS) or trustStore not found. " +
|
||||
"Please either copy your existing keys and certificates from another node, " +
|
||||
"or if you don't have one yet, fill out the config file and run corda.jar initial-registration. " +
|
||||
"Read more at: https://docs.corda.net/permissioning.html"
|
||||
"or if you don't have one yet, fill out the config file and run corda.jar initial-registration."
|
||||
}
|
||||
} catch (e: KeyStoreException) {
|
||||
throw IllegalArgumentException("At least one of the keystores or truststore passwords does not match configuration.")
|
||||
@ -1196,6 +1193,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
*/
|
||||
override fun jdbcSession(): Connection = RestrictedConnection(database.createSession())
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
override fun <T : Any?> withEntityManager(block: EntityManager.() -> T): T {
|
||||
return database.transaction(useErrorHandler = false) {
|
||||
session.flush()
|
||||
@ -1210,7 +1208,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
connection.rollback(savepoint)
|
||||
}
|
||||
}
|
||||
} catch (e: PersistenceException) {
|
||||
} catch (e: Exception) {
|
||||
if (manager.transaction.rollbackOnly) {
|
||||
connection.rollback(savepoint)
|
||||
}
|
||||
@ -1359,7 +1357,7 @@ fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfi
|
||||
NodeDatabaseErrors.COULD_NOT_CONNECT,
|
||||
cause = ex)
|
||||
ex.cause is ClassNotFoundException -> throw CouldNotCreateDataSourceException(
|
||||
"Could not find the database driver class. Please add it to the 'drivers' folder. See: https://docs.corda.net/corda-configuration-file.html",
|
||||
"Could not find the database driver class. Please add it to the 'drivers' folder.",
|
||||
NodeDatabaseErrors.MISSING_DRIVER)
|
||||
ex is OutstandingDatabaseChangesException -> throw (DatabaseIncompatibleException(ex.message))
|
||||
else ->
|
||||
|
@ -84,19 +84,18 @@ object CheckpointVerifier {
|
||||
sealed class CheckpointIncompatibleException(override val message: String) : Exception() {
|
||||
class CannotBeDeserialisedException(val e: Exception) : CheckpointIncompatibleException(
|
||||
"Found checkpoint that cannot be deserialised using the current Corda version. Please revert to the previous version of Corda, " +
|
||||
"drain your node (see https://docs.corda.net/upgrading-cordapps.html#flow-drains), and try again. Cause: ${e.message}")
|
||||
"drain your node, and try again. Cause: ${e.message}")
|
||||
|
||||
class SubFlowCoreVersionIncompatibleException(val flowClass: Class<out FlowLogic<*>>, oldVersion: Int) : CheckpointIncompatibleException(
|
||||
"Found checkpoint for flow: $flowClass that is incompatible with the current Corda platform. Please revert to the previous " +
|
||||
"version of Corda (version $oldVersion), drain your node (see https://docs.corda.net/upgrading-cordapps.html#flow-drains), and try again.")
|
||||
"version of Corda (version $oldVersion), drain your node, and try again.")
|
||||
|
||||
class FlowVersionIncompatibleException(val flowClass: Class<out FlowLogic<*>>, val cordapp: Cordapp, oldHash: SecureHash) : CheckpointIncompatibleException(
|
||||
"Found checkpoint for flow: $flowClass that is incompatible with the current installed version of ${cordapp.name}. " +
|
||||
"Please reinstall the previous version of the CorDapp (with hash: $oldHash), drain your node " +
|
||||
"(see https://docs.corda.net/upgrading-cordapps.html#flow-drains), and try again.")
|
||||
"Please reinstall the previous version of the CorDapp (with hash: $oldHash), drain your node, and try again.")
|
||||
|
||||
class CordappNotInstalledException(classNotFound: String) : CheckpointIncompatibleException(
|
||||
"Found checkpoint for CorDapp that is no longer installed. Specifically, could not find class $classNotFound. Please install the " +
|
||||
"missing CorDapp, drain your node (see https://docs.corda.net/upgrading-cordapps.html#flow-drains), and try again.")
|
||||
"missing CorDapp, drain your node, and try again.")
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,6 @@ open class NodeStartup : NodeStartupLogging {
|
||||
|
||||
if (!certDirectory.isDirectory()) {
|
||||
printError("Unable to access certificates directory ${certDirectory}. This could be because the node has not been registered with the Identity Operator.")
|
||||
printError("Please see https://docs.corda.net/joining-a-compatibility-zone.html for more information.")
|
||||
printError("Node will now shutdown.")
|
||||
return false
|
||||
}
|
||||
@ -350,9 +349,7 @@ open class NodeStartup : NodeStartupLogging {
|
||||
//
|
||||
// Also see https://bugs.openjdk.java.net/browse/JDK-8143378
|
||||
val messages = listOf(
|
||||
"Your computer took over a second to resolve localhost due an incorrect configuration. Corda will work but start very slowly until this is fixed. ",
|
||||
"Please see https://docs.corda.net/troubleshooting.html#slow-localhost-resolution for information on how to fix this. ",
|
||||
"It will only take a few seconds for you to resolve."
|
||||
"Your computer took over a second to resolve localhost due an incorrect configuration. Corda will work but start very slowly until this is fixed."
|
||||
)
|
||||
logger.warn(messages.joinToString(""))
|
||||
Emoji.renderIfSupported {
|
||||
|
@ -36,6 +36,7 @@ object ConfigHelper {
|
||||
private const val UPPERCASE_PROPERTY_PREFIX = "CORDA."
|
||||
|
||||
private val log = LoggerFactory.getLogger(javaClass)
|
||||
@Suppress("LongParameterList")
|
||||
fun loadConfig(baseDirectory: Path,
|
||||
configFile: Path = baseDirectory / "node.conf",
|
||||
allowMissingConfig: Boolean = false,
|
||||
@ -88,7 +89,15 @@ object ConfigHelper {
|
||||
return ConfigFactory.parseMap(
|
||||
toProperties()
|
||||
.mapKeys {
|
||||
var newKey = (it.key as String)
|
||||
val original = it.key as String
|
||||
|
||||
// Reject environment variable that are in all caps
|
||||
// since these cannot be properties.
|
||||
if (original == original.toUpperCase()){
|
||||
return@mapKeys original
|
||||
}
|
||||
|
||||
var newKey = original
|
||||
.replace('_', '.')
|
||||
.replace(UPPERCASE_PROPERTY_PREFIX, CORDA_PROPERTY_PREFIX)
|
||||
|
||||
@ -175,4 +184,4 @@ fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500N
|
||||
else -> throw IllegalArgumentException("CryptoService not supported.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -563,7 +563,7 @@ val Class<out FlowLogic<*>>.flowVersionAndInitiatingClass: Pair<Int, Class<out F
|
||||
current = current.superclass
|
||||
?: return found
|
||||
?: throw IllegalArgumentException("$name, as a flow that initiates other flows, must be annotated with " +
|
||||
"${InitiatingFlow::class.java.name}. See https://docs.corda.net/api-flows.html#flowlogic-annotations.")
|
||||
"${InitiatingFlow::class.java.name}.")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,8 +339,7 @@ class SingleThreadedStateMachineManager(
|
||||
|
||||
private fun checkQuasarJavaAgentPresence() {
|
||||
check(JavaAgent.isActive()) {
|
||||
"""Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM.
|
||||
#See https://docs.corda.net/head/testing.html#running-tests-in-intellij - 'Fiber classes not instrumented' for more details.""".trimMargin("#")
|
||||
"Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM."
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -626,8 +626,7 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
|
||||
e.message?.let { message ->
|
||||
if (message.contains("Not an entity"))
|
||||
throw VaultQueryException("""
|
||||
Please register the entity '${entityStateClass.name}'
|
||||
See https://docs.corda.net/api-persistence.html#custom-schema-registration for more information""")
|
||||
Please register the entity '${entityStateClass.name}'.""")
|
||||
}
|
||||
throw VaultQueryException("Parsing error: ${e.message}")
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ object ContractJarTestUtils {
|
||||
val fileManager = compiler.getStandardFileManager(null, null, null)
|
||||
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, listOf(workingDir.toFile()))
|
||||
|
||||
compiler.getTask(System.out.writer(), fileManager, null, null, null, listOf(source)).call()
|
||||
compiler.getTask(System.out.writer(), fileManager, null, listOf("-source", "8", "-target", "8"), null, listOf(source)).call()
|
||||
val outFile = fileManager.getFileForInput(StandardLocation.CLASS_OUTPUT, packages.joinToString("."), "$className.class")
|
||||
return Paths.get(outFile.name)
|
||||
}
|
||||
|
@ -112,8 +112,6 @@ class JarSignatureCollectorTest {
|
||||
"""
|
||||
Mismatch between signers [O=Alice Corp, L=Madrid, C=ES, O=Bob Plc, L=Rome, C=IT] for file _signable1
|
||||
and signers [O=Bob Plc, L=Rome, C=IT] for file _signable2.
|
||||
See https://docs.corda.net/api-contract-constraints.html#signature-constraints for details of the
|
||||
constraints applied to attachment signatures.
|
||||
""".trimIndent().replace('\n', ' ')
|
||||
) { dir.getJarSigners(FILENAME) }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user