NOTICK Merge OS 4.6 -> 4.7

This commit is contained in:
Ross Nicoll 2020-10-15 09:01:55 +01:00 committed by GitHub
commit 8ef739b555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 98 additions and 48 deletions

View File

@ -21,7 +21,7 @@ import java.time.Instant
* *
* @property minimumPlatformVersion Minimum version of Corda platform that is required for nodes in the network. * @property minimumPlatformVersion Minimum version of Corda platform that is required for nodes in the network.
* @property notaries List of well known and trusted notary identities with information on validation type. * @property notaries List of well known and trusted notary identities with information on validation type.
* @property maxMessageSize This is currently ignored. However, it will be wired up in a future release. * @property maxMessageSize Maximum allowed size in bytes of an individual message sent over the wire.
* @property maxTransactionSize Maximum permitted transaction size in bytes. * @property maxTransactionSize Maximum permitted transaction size in bytes.
* @property modifiedTime ([AutoAcceptable]) Last modification time of network parameters set. * @property modifiedTime ([AutoAcceptable]) Last modification time of network parameters set.
* @property epoch ([AutoAcceptable]) Version number of the network parameters. Starting from 1, this will always increment on each new set * @property epoch ([AutoAcceptable]) Version number of the network parameters. Starting from 1, this will always increment on each new set

View File

@ -43,6 +43,7 @@ import net.corda.coretesting.internal.NettyTestServer
import net.corda.testing.internal.createDevIntermediateCaCertPath import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.coretesting.internal.stubs.CertificateStoreStubs
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.checkValidity import net.corda.nodeapi.internal.crypto.checkValidity
import net.corda.nodeapi.internal.crypto.getSupportedKey import net.corda.nodeapi.internal.crypto.getSupportedKey
@ -50,6 +51,7 @@ import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
import net.corda.nodeapi.internal.crypto.save import net.corda.nodeapi.internal.crypto.save
import net.corda.nodeapi.internal.crypto.toBc import net.corda.nodeapi.internal.crypto.toBc
import net.corda.nodeapi.internal.crypto.x509 import net.corda.nodeapi.internal.crypto.x509
import net.corda.nodeapi.internal.crypto.x509Certificates
import net.corda.testing.internal.IS_OPENJ9 import net.corda.testing.internal.IS_OPENJ9
import net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPrivateKey
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -570,4 +572,16 @@ class X509UtilitiesTest {
cert.checkValidity({ "Error text" }, { }, Date.from(today.toInstant() + 51.days)) cert.checkValidity({ "Error text" }, { }, Date.from(today.toInstant() + 51.days))
} }
} }
@Test(timeout = 300_000)
fun `check certificate serial number`() {
val keyPair = generateKeyPair()
val subject = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
val cert = X509Utilities.createSelfSignedCACertificate(subject, keyPair)
assertTrue(cert.serialNumber.signum() > 0)
assertEquals(127, cert.serialNumber.bitLength())
val serialized = X509Utilities.buildCertPath(cert).encoded
val deserialized = X509CertificateFactory().delegate.generateCertPath(serialized.inputStream()).x509Certificates.first()
assertEquals(cert.serialNumber, deserialized.serialNumber)
}
} }

View File

@ -2,7 +2,7 @@ package net.corda.nodeapi.internal.crypto
import net.corda.core.CordaOID import net.corda.core.CordaOID
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.newSecureRandom
import net.corda.core.internal.* import net.corda.core.internal.*
import net.corda.core.utilities.days import net.corda.core.utilities.days
import net.corda.core.utilities.millis import net.corda.core.utilities.millis
@ -35,6 +35,8 @@ import java.time.Instant
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import java.util.* import java.util.*
import javax.security.auth.x500.X500Principal import javax.security.auth.x500.X500Principal
import kotlin.experimental.and
import kotlin.experimental.or
object X509Utilities { object X509Utilities {
// Note that this default value only applies to BCCryptoService. Other implementations of CryptoService may have to use different // Note that this default value only applies to BCCryptoService. Other implementations of CryptoService may have to use different
@ -58,6 +60,7 @@ object X509Utilities {
const val TLS_CERTIFICATE_DAYS_TO_EXPIRY_WARNING_THRESHOLD = 30 const val TLS_CERTIFICATE_DAYS_TO_EXPIRY_WARNING_THRESHOLD = 30
private const val KEY_ALIAS_REGEX = "[a-z0-9-]+" private const val KEY_ALIAS_REGEX = "[a-z0-9-]+"
private const val KEY_ALIAS_MAX_LENGTH = 100 private const val KEY_ALIAS_MAX_LENGTH = 100
private const val CERTIFICATE_SERIAL_NUMBER_LENGTH = 16
/** /**
* Checks if the provided key alias does not exceed maximum length and * Checks if the provided key alias does not exceed maximum length and
@ -184,7 +187,7 @@ object X509Utilities {
nameConstraints: NameConstraints? = null, nameConstraints: NameConstraints? = null,
crlDistPoint: String? = null, crlDistPoint: String? = null,
crlIssuer: X500Name? = null): X509v3CertificateBuilder { crlIssuer: X500Name? = null): X509v3CertificateBuilder {
val serial = BigInteger.valueOf(random63BitValue()) val serial = generateCertificateSerialNumber()
val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } }) val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } })
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded)) val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded))
val role = certificateType.role val role = certificateType.role
@ -364,6 +367,15 @@ object X509Utilities {
builder.addExtension(Extension.cRLDistributionPoints, false, CRLDistPoint(arrayOf(distPoint))) builder.addExtension(Extension.cRLDistributionPoints, false, CRLDistPoint(arrayOf(distPoint)))
} }
} }
@Suppress("MagicNumber")
private fun generateCertificateSerialNumber(): BigInteger {
val bytes = ByteArray(CERTIFICATE_SERIAL_NUMBER_LENGTH)
newSecureRandom().nextBytes(bytes)
// Set highest byte to 01xxxxxx to ensure positive sign and constant bit length.
bytes[0] = bytes[0].and(0x3F).or(0x40)
return BigInteger(bytes)
}
} }
// Assuming cert type to role is 1:1 // Assuming cert type to role is 1:1

View File

@ -23,9 +23,9 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.Parameterized import org.junit.runners.Parameterized
import java.sql.Connection
import java.sql.Statement import java.sql.Statement
import java.util.* import java.util.*
import javax.sql.DataSource
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
/* /*
@ -34,7 +34,7 @@ import kotlin.test.assertFailsWith
*/ */
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) { class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) {
private lateinit var node: NodeWithInfo private var node: NodeWithInfo? = null
private lateinit var client: CordaRPCClient private lateinit var client: CordaRPCClient
private lateinit var db: UsersDB private lateinit var db: UsersDB
@ -97,8 +97,9 @@ class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) {
) )
) )
node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig) node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig).also { node ->
client = CordaRPCClient(node.node.configuration.rpcOptions.address) client = CordaRPCClient(node.node.configuration.rpcOptions.address)
}
} }
@Test(timeout=300_000) @Test(timeout=300_000)
@ -219,6 +220,7 @@ class AuthDBTests : NodeBasedTest(cordappPackages = CORDAPPS) {
@After @After
fun tearDown() { fun tearDown() {
node?.node?.stop()
db.close() db.close()
} }
@ -232,7 +234,7 @@ private data class RoleAndPermissions(val role: String, val permissions: List<St
* Manage in-memory DB mocking a users database with the schema expected by Node's security manager * Manage in-memory DB mocking a users database with the schema expected by Node's security manager
*/ */
private class UsersDB(name: String, users: List<UserAndRoles> = emptyList(), roleAndPermissions: List<RoleAndPermissions> = emptyList()) : AutoCloseable { private class UsersDB(name: String, users: List<UserAndRoles> = emptyList(), roleAndPermissions: List<RoleAndPermissions> = emptyList()) : AutoCloseable {
val jdbcUrl = "jdbc:h2:mem:$name;DB_CLOSE_DELAY=-1" val jdbcUrl = "jdbc:h2:mem:$name"
companion object { companion object {
const val DB_CREATE_SCHEMA = """ const val DB_CREATE_SCHEMA = """
@ -273,36 +275,34 @@ private class UsersDB(name: String, users: List<UserAndRoles> = emptyList(), rol
} }
} }
private val dataSource: DataSource private val connection: Connection
private inline fun session(statement: (Statement) -> Unit) { private inline fun session(statement: (Statement) -> Unit) {
dataSource.connection.use { connection.createStatement().use(statement)
it.autoCommit = false connection.commit()
it.createStatement().use(statement)
it.commit()
}
} }
init { init {
dataSource = DataSourceFactory.createDataSource(Properties().apply { require(users.map { it.username }.toSet().size == users.size) {
"Duplicate username in input"
}
connection = DataSourceFactory.createDataSource(Properties().apply {
put("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource") put("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
put("dataSource.url", jdbcUrl) put("dataSource.url", jdbcUrl)
}, false) }, false)
.connection
.apply {
autoCommit = false
}
session { session {
it.execute(DB_CREATE_SCHEMA) it.execute(DB_CREATE_SCHEMA)
} }
require(users.map { it.username }.toSet().size == users.size) {
"Duplicate username in input"
}
users.forEach { insert(it) } users.forEach { insert(it) }
roleAndPermissions.forEach { insert(it) } roleAndPermissions.forEach { insert(it) }
} }
override fun close() { override fun close() {
dataSource.connection.use { // Close the connection, at which point the database will shut down
it.createStatement().use { connection.close()
it.execute("DROP ALL OBJECTS")
}
}
} }
} }

View File

@ -89,18 +89,15 @@ class ScheduledFlowIntegrationTests {
private fun MutableList<CordaFuture<*>>.getOrThrowAll() { private fun MutableList<CordaFuture<*>>.getOrThrowAll() {
forEach { forEach {
try { it.getOrThrow()
it.getOrThrow()
} catch (ex: Exception) {
}
} }
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun `test that when states are being spent at the same time that schedules trigger everything is processed`() { fun `test that when states are being spent at the same time that schedules trigger everything is processed`() {
driver(DriverParameters( driver(DriverParameters(
startNodesInProcess = true, startNodesInProcess = false,
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, cordappWithPackages("net.corda.testMessage"), enclosedCordapp()) cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, cordappWithPackages("net.corda.testMessage", "net.corda.testing.core"), enclosedCordapp())
)) { )) {
val N = 23 val N = 23
val rpcUser = User("admin", "admin", setOf("ALL")) val rpcUser = User("admin", "admin", setOf("ALL"))
@ -127,6 +124,7 @@ class ScheduledFlowIntegrationTests {
scheduledFor scheduledFor
).returnValue) ).returnValue)
} }
initialiseFutures.getOrThrowAll() initialiseFutures.getOrThrowAll()
val spendAttemptFutures = mutableListOf<CordaFuture<*>>() val spendAttemptFutures = mutableListOf<CordaFuture<*>>()
@ -134,6 +132,7 @@ class ScheduledFlowIntegrationTests {
spendAttemptFutures.add(aliceClient.proxy.startFlow(::AnotherFlow, (i).toString()).returnValue) spendAttemptFutures.add(aliceClient.proxy.startFlow(::AnotherFlow, (i).toString()).returnValue)
spendAttemptFutures.add(bobClient.proxy.startFlow(::AnotherFlow, (i + 100).toString()).returnValue) spendAttemptFutures.add(bobClient.proxy.startFlow(::AnotherFlow, (i + 100).toString()).returnValue)
} }
spendAttemptFutures.getOrThrowAll() spendAttemptFutures.getOrThrowAll()
// TODO: the queries below are not atomic so we need to allow enough time for the scheduler to finish. Would be better to query scheduler. // TODO: the queries below are not atomic so we need to allow enough time for the scheduler to finish. Would be better to query scheduler.
@ -144,7 +143,7 @@ class ScheduledFlowIntegrationTests {
val bobStates = bobClient.proxy.vaultQuery(ScheduledState::class.java).states.filter { it.state.data.processed } val bobStates = bobClient.proxy.vaultQuery(ScheduledState::class.java).states.filter { it.state.data.processed }
val bobSpentStates = bobClient.proxy.vaultQuery(SpentState::class.java).states val bobSpentStates = bobClient.proxy.vaultQuery(SpentState::class.java).states
assertEquals(aliceStates.count() + aliceSpentStates.count(), N * 2) assertEquals(aliceStates.count() + aliceSpentStates.count(), N * 2)
assertEquals(bobStates.count() + bobSpentStates.count(), N * 2) assertEquals(bobStates.count() + bobSpentStates.count(), N * 2)
assertEquals(aliceSpentStates.count(), bobSpentStates.count()) assertEquals(aliceSpentStates.count(), bobSpentStates.count())

View File

@ -52,6 +52,7 @@ import kotlin.test.assertTrue
class VaultObserverExceptionTest { class VaultObserverExceptionTest {
companion object { companion object {
val waitForFlowDuration = 45.seconds
val log = contextLogger() val log = contextLogger()
private fun testCordapps() = listOf( private fun testCordapps() = listOf(
@ -99,7 +100,7 @@ class VaultObserverExceptionTest {
"Syntax Error in Custom SQL", "Syntax Error in Custom SQL",
CreateStateFlow.errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError) CreateStateFlow.errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError)
).returnValue.then { testControlFuture.complete(false) } ).returnValue.then { testControlFuture.complete(false) }
val foundExpectedException = testControlFuture.getOrThrow(30.seconds) val foundExpectedException = testControlFuture.getOrThrow(waitForFlowDuration)
Assert.assertTrue(foundExpectedException) Assert.assertTrue(foundExpectedException)
} }
@ -133,7 +134,7 @@ class VaultObserverExceptionTest {
"Syntax Error in Custom SQL", "Syntax Error in Custom SQL",
CreateStateFlow.errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError) CreateStateFlow.errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError)
).returnValue.then { testControlFuture.complete(false) } ).returnValue.then { testControlFuture.complete(false) }
val foundExpectedException = testControlFuture.getOrThrow(30.seconds) val foundExpectedException = testControlFuture.getOrThrow(waitForFlowDuration)
Assert.assertTrue(foundExpectedException) Assert.assertTrue(foundExpectedException)
} }
@ -224,7 +225,7 @@ class VaultObserverExceptionTest {
assertFailsWith<TimeoutException>("PersistenceException") { assertFailsWith<TimeoutException>("PersistenceException") {
aliceNode.rpc.startFlow(CreateStateFlow::Initiator, "EntityManager", errorTargetsToNum( aliceNode.rpc.startFlow(CreateStateFlow::Initiator, "EntityManager", errorTargetsToNum(
CreateStateFlow.ErrorTarget.TxInvalidState)) CreateStateFlow.ErrorTarget.TxInvalidState))
.returnValue.getOrThrow(30.seconds) .returnValue.getOrThrow(waitForFlowDuration)
} }
} }
Assert.assertTrue("Flow has not been to hospital", counter > 0) Assert.assertTrue("Flow has not been to hospital", counter > 0)
@ -260,7 +261,7 @@ class VaultObserverExceptionTest {
CreateStateFlow.ErrorTarget.TxInvalidState, CreateStateFlow.ErrorTarget.TxInvalidState,
CreateStateFlow.ErrorTarget.FlowSwallowErrors)) CreateStateFlow.ErrorTarget.FlowSwallowErrors))
val flowResult = flowHandle.returnValue val flowResult = flowHandle.returnValue
assertFailsWith<TimeoutException>("PersistenceException") { flowResult.getOrThrow(30.seconds) } assertFailsWith<TimeoutException>("PersistenceException") { flowResult.getOrThrow(waitForFlowDuration) }
Assert.assertTrue("Flow has not been to hospital", counter > 0) Assert.assertTrue("Flow has not been to hospital", counter > 0)
} }
} }
@ -291,7 +292,7 @@ class VaultObserverExceptionTest {
log.info("Flow has finished") log.info("Flow has finished")
testControlFuture.set(false) testControlFuture.set(false)
} }
Assert.assertTrue("Flow has not been kept in hospital", testControlFuture.getOrThrow(30.seconds)) Assert.assertTrue("Flow has not been kept in hospital", testControlFuture.getOrThrow(waitForFlowDuration))
} }
} }
@ -310,7 +311,7 @@ class VaultObserverExceptionTest {
CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError, CreateStateFlow.ErrorTarget.ServiceSqlSyntaxError,
CreateStateFlow.ErrorTarget.ServiceSwallowErrors)) CreateStateFlow.ErrorTarget.ServiceSwallowErrors))
val flowResult = flowHandle.returnValue val flowResult = flowHandle.returnValue
flowResult.getOrThrow(30.seconds) flowResult.getOrThrow(waitForFlowDuration)
} }
} }
@ -411,7 +412,7 @@ class VaultObserverExceptionTest {
testControlFuture.complete(true) testControlFuture.complete(true)
} }
startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser), startInSameProcess = true).getOrThrow() startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser), startInSameProcess = true).getOrThrow()
assert(testControlFuture.getOrThrow(30.seconds)) assert(testControlFuture.getOrThrow(waitForFlowDuration))
} else { } else {
throw IllegalStateException("Out of process node is still up and running!") throw IllegalStateException("Out of process node is still up and running!")
} }
@ -464,7 +465,7 @@ class VaultObserverExceptionTest {
CreateStateFlow::Initiator, CreateStateFlow::Initiator,
"AllGood", "AllGood",
errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed) errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed)
).returnValue.getOrThrow(30.seconds) ).returnValue.getOrThrow(waitForFlowDuration)
println("Created new state") println("Created new state")
@ -558,7 +559,7 @@ class VaultObserverExceptionTest {
"AllGood", "AllGood",
// should be a hospital exception // should be a hospital exception
errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed) errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed)
).returnValue.getOrThrow(30.seconds) ).returnValue.getOrThrow(waitForFlowDuration)
val flowHandle = aliceNode.rpc.startFlow( val flowHandle = aliceNode.rpc.startFlow(
SendStateFlow::PassErroneousOwnableState, SendStateFlow::PassErroneousOwnableState,
@ -642,7 +643,7 @@ class VaultObserverExceptionTest {
CreateStateFlow::Initiator, CreateStateFlow::Initiator,
"AllGood", "AllGood",
errorTargetsToNum(CreateStateFlow.ErrorTarget.NoError) errorTargetsToNum(CreateStateFlow.ErrorTarget.NoError)
).returnValue.getOrThrow(30.seconds) ).returnValue.getOrThrow(waitForFlowDuration)
aliceNode.rpc.startFlow( aliceNode.rpc.startFlow(
SendStateFlow::PassErroneousOwnableState, SendStateFlow::PassErroneousOwnableState,
@ -722,7 +723,7 @@ class VaultObserverExceptionTest {
CreateStateFlow::Initiator, CreateStateFlow::Initiator,
"AllGood", "AllGood",
errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed) errorTargetsToNum(CreateStateFlow.ErrorTarget.ServiceSqlSyntaxErrorOnConsumed)
).returnValue.getOrThrow(30.seconds) ).returnValue.getOrThrow(waitForFlowDuration)
val flowHandle = aliceNode.rpc.startFlow( val flowHandle = aliceNode.rpc.startFlow(
SendStateFlow::PassErroneousOwnableState, SendStateFlow::PassErroneousOwnableState,
@ -777,7 +778,7 @@ class VaultObserverExceptionTest {
"Flow ${SubscribingRawUpdatesFlow::class.java.name} tried to access VaultService.rawUpdates " + "Flow ${SubscribingRawUpdatesFlow::class.java.name} tried to access VaultService.rawUpdates " +
"- Rx.Observables should only be accessed outside the context of a flow " "- Rx.Observables should only be accessed outside the context of a flow "
) { ) {
flowHandle.returnValue.getOrThrow(30.seconds) flowHandle.returnValue.getOrThrow(waitForFlowDuration)
} }
} }
} }

View File

@ -126,7 +126,9 @@ class RetryFlowMockTest {
ReceiveFlow3.lock.release() ReceiveFlow3.lock.release()
assertTrue(expectedMessagesSent.await(20, TimeUnit.SECONDS)) assertTrue(expectedMessagesSent.await(20, TimeUnit.SECONDS))
assertEquals(3, messagesSent.size) assertEquals(3, messagesSent.size)
assertNull(messagesSent.last().senderUUID) // CORDA-4045: We can't be sure that the last message sent will be the last we record, so
// instead check we have exactly one message (the first) with sender UUID
assertNotNull(messagesSent.singleOrNull { it.senderUUID != null })
} }
@Test(timeout=300_000) @Test(timeout=300_000)

View File

@ -13,11 +13,12 @@ object DatabaseSnapshot {
return resourceUri.openStream() return resourceUri.openStream()
} }
fun databaseFilename(baseDirectory: Path) = baseDirectory.resolve(databaseName)
fun copyDatabaseSnapshot(baseDirectory: Path) { fun copyDatabaseSnapshot(baseDirectory: Path) {
getDatabaseSnapshotStream().use { stream -> getDatabaseSnapshotStream().use { stream ->
Files.createDirectories(baseDirectory) Files.createDirectories(baseDirectory)
val path = baseDirectory.resolve(databaseName) Files.copy(stream, databaseFilename(baseDirectory))
Files.copy(stream, path)
} }
} }
} }

View File

@ -36,6 +36,7 @@ import net.corda.core.internal.cordapp.CordappImpl.Companion.MIN_PLATFORM_VERSIO
import net.corda.core.internal.cordapp.CordappImpl.Companion.TARGET_PLATFORM_VERSION import net.corda.core.internal.cordapp.CordappImpl.Companion.TARGET_PLATFORM_VERSION
import net.corda.core.internal.cordapp.get import net.corda.core.internal.cordapp.get
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.deleteIfExists
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.isRegularFile import net.corda.core.internal.isRegularFile
import net.corda.core.internal.list import net.corda.core.internal.list
@ -57,6 +58,7 @@ import net.corda.core.utilities.toHexString
import net.corda.coretesting.internal.stubs.CertificateStoreStubs import net.corda.coretesting.internal.stubs.CertificateStoreStubs
import net.corda.node.NodeRegistrationOption import net.corda.node.NodeRegistrationOption
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.internal.DataSourceFactory
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.internal.NodeWithInfo import net.corda.node.internal.NodeWithInfo
import net.corda.node.internal.clientSslOptionsCompatibleWith import net.corda.node.internal.clientSslOptionsCompatibleWith
@ -268,14 +270,17 @@ class DriverDSLImpl(
val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB") val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
val config = createConfig(name, parameters, p2pAddress) val config = createConfig(name, parameters, p2pAddress)
if (premigrateH2Database && isH2Database(config)) { if (isH2Database(config) && !inMemoryDB) {
if (!inMemoryDB) { if (premigrateH2Database) {
try { try {
DatabaseSnapshot.copyDatabaseSnapshot(config.corda.baseDirectory) DatabaseSnapshot.copyDatabaseSnapshot(config.corda.baseDirectory)
} catch (ex: java.nio.file.FileAlreadyExistsException) { } catch (ex: java.nio.file.FileAlreadyExistsException) {
log.warn("Database already exists on disk, not attempting to pre-migrate database.") log.warn("Database already exists on disk, not attempting to pre-migrate database.")
} }
} }
shutdownManager.registerShutdown {
shutdownAndDeleteDatabase(config.corda)
}
} }
val registrationFuture = if (compatibilityZone?.rootCert != null) { val registrationFuture = if (compatibilityZone?.rootCert != null) {
// We don't need the network map to be available to be able to register the node // We don't need the network map to be available to be able to register the node
@ -1141,6 +1146,17 @@ class DriverDSLImpl(
private fun Map<String, Any>.removeResolvedClasspath(): Map<String, Any> { private fun Map<String, Any>.removeResolvedClasspath(): Map<String, Any> {
return filterNot { it.key == "java.class.path" } return filterNot { it.key == "java.class.path" }
} }
private fun shutdownAndDeleteDatabase(config: NodeConfiguration) {
DataSourceFactory.createDataSource(config.dataSourceProperties).also { dataSource ->
dataSource.connection.use { connection ->
connection.createStatement().use { statement ->
statement.execute("SHUTDOWN")
}
}
}
DatabaseSnapshot.databaseFilename(config.baseDirectory).deleteIfExists()
}
} }
} }

View File

@ -16,6 +16,7 @@ import net.corda.core.internal.NetworkParametersStorage
import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.deleteIfExists
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.notary.NotaryService
import net.corda.core.internal.uncheckedCast import net.corda.core.internal.uncheckedCast
@ -62,6 +63,7 @@ import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.node.DatabaseSnapshot
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetworkNotarySpec import net.corda.testing.node.MockNetworkNotarySpec
import net.corda.testing.node.MockNetworkParameters import net.corda.testing.node.MockNetworkParameters
@ -599,7 +601,10 @@ open class InternalMockNetwork(cordappPackages: List<String> = emptyList(),
cordappClassLoader.use { _ -> cordappClassLoader.use { _ ->
// Serialization env must be unset even if other parts of this method fail. // Serialization env must be unset even if other parts of this method fail.
serializationEnv.use { serializationEnv.use {
nodes.forEach { it.started?.dispose() } nodes.forEach { node ->
node.started?.dispose()
DatabaseSnapshot.databaseFilename(node.configuration.baseDirectory).deleteIfExists()
}
} }
messagingNetwork.stop() messagingNetwork.stop()
} }