mirror of
https://github.com/corda/corda.git
synced 2024-12-25 07:31:10 +00:00
Merge pull request #3613 from corda/kat/bakport/corda-1804
CORDA-1499, CORDA-1804 (#3607)
This commit is contained in:
commit
3da07a1105
@ -66,6 +66,8 @@ Version 3.2
|
||||
the same server. Current ``compatibilityZoneURL`` configurations remain valid. See both :doc:`corda-configuration-file`
|
||||
and :doc:`permissioning` for details.
|
||||
|
||||
* Table name with a typo changed from ``NODE_ATTCHMENTS_CONTRACTS`` to ``NODE_ATTACHMENTS_CONTRACTS``.
|
||||
|
||||
.. _changelog_v3.1:
|
||||
|
||||
Version 3.1
|
||||
|
@ -82,6 +82,8 @@ class CordaPersistence(
|
||||
// Check not in read-only mode.
|
||||
transaction {
|
||||
check(!connection.metaData.isReadOnly) { "Database should not be readonly." }
|
||||
|
||||
checkCorrectAttachmentsContractsTableName(connection)
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,3 +247,18 @@ fun <T : Any> rx.Observable<T>.wrapWithDatabaseTransaction(db: CordaPersistence?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IncompatibleAttachmentsContractsTableName(override val message: String?, override val cause: Throwable? = null) : Exception()
|
||||
|
||||
private fun checkCorrectAttachmentsContractsTableName(connection: Connection) {
|
||||
val correctName = "NODE_ATTACHMENTS_CONTRACTS"
|
||||
val incorrectV30Name = "NODE_ATTACHMENTS_CONTRACT_CLASS_NAME"
|
||||
val incorrectV31Name = "NODE_ATTCHMENTS_CONTRACTS"
|
||||
|
||||
fun warning(incorrectName: String, version: String) = "The database contains the older table name $incorrectName instead of $correctName, see upgrade notes to migrate from Corda database version $version https://docs.corda.net/head/upgrade-notes.html."
|
||||
|
||||
if (!connection.metaData.getTables(null, null, correctName, null).next()) {
|
||||
if (connection.metaData.getTables(null, null, incorrectV30Name, null).next()) { throw IncompatibleAttachmentsContractsTableName(warning(incorrectV30Name, "3.0")) }
|
||||
if (connection.metaData.getTables(null, null, incorrectV31Name, null).next()) { throw IncompatibleAttachmentsContractsTableName(warning(incorrectV31Name, "3.1")) }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
package net.corda.node.persistence
|
||||
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.internal.packageName
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.services.Permissions
|
||||
import net.corda.test.node.Message
|
||||
import net.corda.test.node.MessageState
|
||||
import net.corda.test.node.SendMessageFlow
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.driver.internal.RandomFree
|
||||
import net.corda.testing.node.User
|
||||
import org.junit.Test
|
||||
import java.nio.file.Path
|
||||
import java.sql.DriverManager
|
||||
import kotlin.test.*
|
||||
|
||||
class FailNodeOnNotMigratedAttachmentContractsTableNameTests {
|
||||
@Test
|
||||
fun `node fails when detecting table name not migrated from version 3 dot 0`() {
|
||||
`node fails when not detecting compatible table name`("NODE_ATTACHMENTS_CONTRACTS", "NODE_ATTACHMENTS_CONTRACT_CLASS_NAME")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `node fails when detecting table name not migrated from version 3 dot 1`() {
|
||||
`node fails when not detecting compatible table name`("NODE_ATTACHMENTS_CONTRACTS", "NODE_ATTCHMENTS_CONTRACTS")
|
||||
}
|
||||
|
||||
fun `node fails when not detecting compatible table name`(tableNameFromMapping: String, tableNameInDB: String) {
|
||||
val user = User("mark", "dadada", setOf(Permissions.startFlow<SendMessageFlow>(), Permissions.invokeRpc("vaultQuery")))
|
||||
val message = Message("Hello world!")
|
||||
val baseDir: Path = driver(DriverParameters(startNodesInProcess = true,
|
||||
portAllocation = RandomFree, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) {
|
||||
val (nodeName, baseDir) = {
|
||||
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
|
||||
val nodeName = nodeHandle.nodeInfo.singleIdentity().name
|
||||
CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
|
||||
it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow()
|
||||
}
|
||||
nodeHandle.stop()
|
||||
Pair(nodeName, nodeHandle.baseDirectory)
|
||||
}()
|
||||
|
||||
// replace the correct table name with one from the former release
|
||||
DriverManager.getConnection("jdbc:h2:file://$baseDir/persistence", "sa", "").use {
|
||||
it.createStatement().execute("ALTER TABLE $tableNameFromMapping RENAME TO $tableNameInDB")
|
||||
it.commit()
|
||||
}
|
||||
assertFailsWith(net.corda.nodeapi.internal.persistence.IncompatibleAttachmentsContractsTableName::class) {
|
||||
val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user)).getOrThrow()
|
||||
nodeHandle.stop()
|
||||
}
|
||||
baseDir
|
||||
}
|
||||
|
||||
// check that the node didn't recreated the correct table matching it's entity mapping
|
||||
val (hasTableFromMapping, hasTableFromDB) = DriverManager.getConnection("jdbc:h2:file://$baseDir/persistence", "sa", "").use {
|
||||
Pair(it.metaData.getTables(null, null, tableNameFromMapping, null).next(),
|
||||
it.metaData.getTables(null, null, tableNameInDB, null).next())
|
||||
}
|
||||
assertFalse(hasTableFromMapping)
|
||||
assertTrue(hasTableFromDB)
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package net.corda.node.internal
|
||||
|
||||
import com.codahale.metrics.JmxReporter
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.internal.Emoji
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.concurrent.thenMatch
|
||||
import net.corda.core.internal.div
|
||||
@ -74,6 +75,13 @@ open class Node(configuration: NodeConfiguration,
|
||||
LoggerFactory.getLogger(loggerName).info(msg)
|
||||
}
|
||||
|
||||
fun printWarning(message: String) {
|
||||
Emoji.renderIfSupported {
|
||||
println("ATTENTION: $message")
|
||||
}
|
||||
staticLog.warn(message)
|
||||
}
|
||||
|
||||
internal fun failStartUp(message: String): Nothing {
|
||||
println(message)
|
||||
println("Corda will now exit...")
|
||||
|
@ -17,6 +17,7 @@ import net.corda.node.shell.InteractiveShell
|
||||
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
||||
import net.corda.node.utilities.registration.NetworkRegistrationHelper
|
||||
import net.corda.nodeapi.internal.addShutdownHook
|
||||
import net.corda.nodeapi.internal.persistence.IncompatibleAttachmentsContractsTableName
|
||||
import org.fusesource.jansi.Ansi
|
||||
import org.fusesource.jansi.AnsiConsole
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler
|
||||
@ -113,6 +114,10 @@ open class NodeStartup(val args: Array<String>) {
|
||||
try {
|
||||
cmdlineOptions.baseDirectory.createDirectories()
|
||||
startNode(conf, versionInfo, startTime, cmdlineOptions)
|
||||
} catch (e: IncompatibleAttachmentsContractsTableName) {
|
||||
e.message?.let { Node.printWarning(it) }
|
||||
logger.error(e.message)
|
||||
return false
|
||||
} catch (e: Exception) {
|
||||
if (e is Errors.NativeIoException && e.message?.contains("Address already in use") == true) {
|
||||
logger.error("One of the ports required by the Corda node is already in use.")
|
||||
|
Loading…
Reference in New Issue
Block a user