Merge pull request #3613 from corda/kat/bakport/corda-1804

CORDA-1499, CORDA-1804  (#3607)
This commit is contained in:
Michele Sollecito 2018-07-16 10:39:30 +01:00 committed by GitHub
commit 3da07a1105
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 99 additions and 0 deletions

View File

@ -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

View File

@ -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")) }
}
}

View File

@ -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)
}
}

View File

@ -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...")

View File

@ -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.")