CORDA-3200 Use PersistentIdentityMigrationBuilder instead of schema a… (#5449)

* CORDA-3200 Use PersistentIdentityMigrationBuilder instead of schema and correctly name table using node prefix

* CORDA-3200 Remove hacky test migration from PersistentIdentityMigrationNewTable into a unit test to fix postgres failure
This commit is contained in:
willhr3 2019-09-10 10:51:38 +01:00 committed by Roger Willis
parent eece19cce0
commit 4fb1787f1e
4 changed files with 56 additions and 121 deletions

View File

@ -44,26 +44,14 @@ class PersistentIdentityMigrationNewTable : CordaMigration() {
logger.error("Cannot migrate persistent states: Liquibase failed to provide a suitable database connection") logger.error("Cannot migrate persistent states: Liquibase failed to provide a suitable database connection")
throw PersistentIdentitiesMigrationException("Cannot migrate persistent states as liquibase failed to provide a suitable database connection") throw PersistentIdentitiesMigrationException("Cannot migrate persistent states as liquibase failed to provide a suitable database connection")
} }
initialiseNodeServices(database, setOf(PersistentIdentitiesMigrationSchemaV1)) initialiseNodeServices(database, setOf(PersistentIdentitiesMigrationSchemaBuilder.getMappedSchema()))
val connection = database.connection as JdbcConnection val connection = database.connection as JdbcConnection
doAndTestMigration(connection)
}
private fun doAndTestMigration(connection: JdbcConnection) {
val alice = TestIdentity(CordaX500Name("Alice Corp", "Madrid", "ES"), 70)
val pkHash = addTestMapping(connection, alice)
// Extract data from old table needed to populate the new table
val keyPartiesMap = extractKeyParties(connection) val keyPartiesMap = extractKeyParties(connection)
keyPartiesMap.forEach { keyPartiesMap.forEach {
insertEntry(connection, it) insertEntry(connection, it)
} }
verifyTestMigration(connection, pkHash, alice.name.toString())
deleteTestMapping(connection, pkHash)
} }
private fun extractKeyParties(connection: JdbcConnection): Map<String, CordaX500Name> { private fun extractKeyParties(connection: JdbcConnection): Map<String, CordaX500Name> {
@ -104,41 +92,6 @@ class PersistentIdentityMigrationNewTable : CordaMigration() {
override fun validate(database: Database?): ValidationErrors? { override fun validate(database: Database?): ValidationErrors? {
return null return null
} }
private fun addTestMapping(connection: JdbcConnection, testIdentity: TestIdentity): String {
val pkHash = UUID.randomUUID().toString()
val cert = testIdentity.identity.certPath.encoded
connection.prepareStatement("INSERT INTO node_identities (pk_hash, identity_value) VALUES (?,?)").use {
it.setString(1, pkHash)
it.setBytes(2, cert)
it.executeUpdate()
}
return pkHash
}
private fun deleteTestMapping(connection: JdbcConnection, pkHash: String) {
connection.prepareStatement("DELETE FROM node_identities WHERE pk_hash = ?").use {
it.setString(1, pkHash)
it.executeUpdate()
}
}
private fun verifyTestMigration(connection: JdbcConnection, pk: String, name: String) {
connection.createStatement().use {
try {
val rs = it.executeQuery("SELECT (pk_hash, name) FROM node_identities_no_cert")
while (rs.next()) {
val result = rs.getString(1)
require(result.contains(pk))
require(result.contains(name))
}
rs.close()
} catch (e: Exception) {
logger.error(e.localizedMessage)
}
}
}
} }
/** /**
@ -150,49 +103,17 @@ class PersistentIdentityMigrationNewTable : CordaMigration() {
*/ */
object PersistentIdentitiesMigrationSchema object PersistentIdentitiesMigrationSchema
object PersistentIdentitiesMigrationSchemaV1 : MappedSchema(schemaFamily = PersistentIdentitiesMigrationSchema.javaClass, version = 1, object PersistentIdentitiesMigrationSchemaBuilder {
mappedTypes = listOf( fun getMappedSchema() =
DBTransactionStorage.DBTransaction::class.java, MappedSchema(schemaFamily = PersistentIdentitiesMigrationSchema.javaClass, version = 1,
PersistentIdentityService.PersistentPublicKeyHashToCertificate::class.java, mappedTypes = listOf(
PersistentIdentityService.PersistentPartyToPublicKeyHash::class.java, DBTransactionStorage.DBTransaction::class.java,
PersistentIdentityService.PersistentPublicKeyHashToParty::class.java, PersistentIdentityService.PersistentPublicKeyHashToCertificate::class.java,
BasicHSMKeyManagementService.PersistentKey::class.java, PersistentIdentityService.PersistentPartyToPublicKeyHash::class.java,
NodeAttachmentService.DBAttachment::class.java, PersistentIdentityService.PersistentPublicKeyHashToParty::class.java,
DBNetworkParametersStorage.PersistentNetworkParameters::class.java BasicHSMKeyManagementService.PersistentKey::class.java,
) NodeAttachmentService.DBAttachment::class.java,
) DBNetworkParametersStorage.PersistentNetworkParameters::class.java
))
class PersistentIdentitiesMigrationException(msg: String, cause: Exception? = null) : Exception(msg, cause) }
class PersistentIdentitiesMigrationException(msg: String, cause: Exception? = null) : Exception(msg, cause)
/**
* A class that encapsulates a test identity containing a [CordaX500Name] and a [KeyPair]. Duplicate of [net.corda.testing.core.TestIdentity]
* to avoid circular dependencies.
*/
private class TestIdentity(val name: CordaX500Name, val keyPair: KeyPair) {
/** Creates an identity with a deterministic [keyPair] i.e. same [entropy] same keyPair. */
@JvmOverloads
constructor(name: CordaX500Name, entropy: Long, signatureScheme: SignatureScheme = Crypto.DEFAULT_SIGNATURE_SCHEME)
: this(name, Crypto.deriveKeyPairFromEntropy(signatureScheme, BigInteger.valueOf(entropy)))
val publicKey: PublicKey get() = keyPair.public
val party: Party = Party(name, publicKey)
val identity: PartyAndCertificate by lazy { getTestPartyAndCertificate(party) } // Often not needed.
fun getTestPartyAndCertificate(party: Party): PartyAndCertificate {
val trustRoot: X509Certificate = DEV_ROOT_CA.certificate
val intermediate: CertificateAndKeyPair = DEV_INTERMEDIATE_CA
val (nodeCaCert, nodeCaKeyPair) = createDevNodeCa(intermediate, party.name)
val identityCert = X509Utilities.createCertificate(
CertificateType.LEGAL_IDENTITY,
nodeCaCert,
nodeCaKeyPair,
party.name.x500Principal,
party.owningKey)
val certPath = X509Utilities.buildCertPath(identityCert, nodeCaCert, intermediate.certificate, trustRoot)
return PartyAndCertificate(certPath)
}
}

View File

@ -5,7 +5,7 @@
logicalFilePath="migration/node-services.changelog-init.xml"> logicalFilePath="migration/node-services.changelog-init.xml">
<changeSet author="R3.Corda" id="add-new-persistence-table"> <changeSet author="R3.Corda" id="add-new-persistence-table">
<createTable tableName="identities_no_cert"> <createTable tableName="node_identities_no_cert">
<column name="pk_hash" type="NVARCHAR(130)"> <column name="pk_hash" type="NVARCHAR(130)">
<constraints nullable="false"/> <constraints nullable="false"/>
</column> </column>

View File

@ -27,8 +27,10 @@ import org.junit.ClassRule
import org.junit.Test import org.junit.Test
import org.mockito.Mockito import org.mockito.Mockito
import java.security.KeyPair import java.security.KeyPair
import java.sql.Connection
import java.time.Clock import java.time.Clock
import java.time.Duration import java.time.Duration
import java.util.*
class PersistentIdentityMigrationNewTableTest{ class PersistentIdentityMigrationNewTableTest{
companion object { companion object {
@ -83,15 +85,9 @@ class PersistentIdentityMigrationNewTableTest{
@Test @Test
fun `migrate identities to new table`() { fun `migrate identities to new table`() {
/** val pkHash = addTestMapping(cordaDB.dataSource.connection, alice)
* TODO - We have to mock every statement/ result to test this properly. PersistentIdentityMigrationNewTable()
* verifyTestMigration(cordaDB.dataSource.connection, pkHash, alice.name.toString())
* The workaround for now is the [PersistentIdentitiesMigration.addTestMapping] and
* [PersistentIdentitiesMigration.deleteTestMapping] methods that allow us to see the migration occur properly during debugging.
*
* Since [PersistentIdentitiesMigration] implements [CordaMigration] the migration will run when the DB is setup.
*/
PersistentIdentityMigrationNewTable()
} }
private fun saveAllIdentities(identities: List<PartyAndCertificate>) { private fun saveAllIdentities(identities: List<PartyAndCertificate>) {
@ -137,4 +133,39 @@ class PersistentIdentityMigrationNewTableTest{
session.save(persistentParams) session.save(persistentParams)
} }
} }
private fun addTestMapping(connection: Connection, testIdentity: TestIdentity): String {
val pkHash = UUID.randomUUID().toString()
val cert = testIdentity.identity.certPath.encoded
connection.prepareStatement("INSERT INTO node_identities (pk_hash, identity_value) VALUES (?,?)").use {
it.setString(1, pkHash)
it.setBytes(2, cert)
it.executeUpdate()
}
return pkHash
}
// private fun deleteTestMapping(connection: Connection, pkHash: String) {
// connection.prepareStatement("DELETE FROM node_identities WHERE pk_hash = ?").use {
// it.setString(1, pkHash)
// it.executeUpdate()
// }
// }
private fun verifyTestMigration(connection: Connection, pk: String, name: String) {
connection.createStatement().use {
try {
val rs = it.executeQuery("SELECT (pk_hash, name) FROM node_identities_no_cert")
while (rs.next()) {
val result = rs.getString(1)
require(result.contains(pk))
require(result.contains(name))
}
rs.close()
} catch (e: Exception) {
println(e.localizedMessage)
}
}
}
} }

View File

@ -1,42 +1,25 @@
package net.corda.node.services.persistence package net.corda.node.services.persistence
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.Amount
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.services.KeyManagementService
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS import net.corda.finance.DOLLARS
import net.corda.finance.`issued by` import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.AbstractCashFlow
import net.corda.finance.issuedBy import net.corda.finance.issuedBy
import net.corda.node.migration.VaultStateMigrationTest.Companion.bankOfCorda
import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.BasicHSMKeyManagementService
import net.corda.node.services.keys.E2ETestKeyManagementService import net.corda.node.services.keys.E2ETestKeyManagementService
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.BOC_NAME
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity import net.corda.testing.core.TestIdentity
import net.corda.testing.internal.TestingNamedCacheFactory import net.corda.testing.internal.TestingNamedCacheFactory
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.internal.FINANCE_CORDAPPS
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
class HibernateColumnConverterTests { class HibernateColumnConverterTests {