Integrate db migration tool - liquibase (#150)

[ENT-996]: integrate Liquibase for data migration
This commit is contained in:
Tudor Malene 2017-12-16 15:58:12 +00:00 committed by GitHub
parent af596cfdde
commit f2194fcfd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 1594 additions and 152 deletions

View File

@ -52,6 +52,7 @@ buildscript {
ext.spring_jdbc_version ='5.0.0.RELEASE' ext.spring_jdbc_version ='5.0.0.RELEASE'
ext.shiro_version = '1.4.0' ext.shiro_version = '1.4.0'
ext.artifactory_plugin_version = constants.getProperty('artifactoryPluginVersion') ext.artifactory_plugin_version = constants.getProperty('artifactoryPluginVersion')
ext.liquibase_version = '3.5.3'
// Update 121 is required for ObjectInputFilter and at time of writing 131 was latest: // Update 121 is required for ObjectInputFilter and at time of writing 131 was latest:
ext.java8_minUpdateVersion = '131' ext.java8_minUpdateVersion = '131'

View File

@ -33,7 +33,7 @@ class IdentitySyncFlowTests {
mockNet = MockNetwork( mockNet = MockNetwork(
networkSendManuallyPumped = false, networkSendManuallyPumped = false,
threadPerNode = true, threadPerNode = true,
cordappPackages = listOf("net.corda.finance.contracts.asset") cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas")
) )
} }

View File

@ -19,6 +19,9 @@ object NodeInfoSchemaV1 : MappedSchema(
version = 1, version = 1,
mappedTypes = listOf(PersistentNodeInfo::class.java, DBPartyAndCertificate::class.java, DBHostAndPort::class.java) mappedTypes = listOf(PersistentNodeInfo::class.java, DBPartyAndCertificate::class.java, DBHostAndPort::class.java)
) { ) {
override val migrationResource = "node-info.changelog-master"
@Entity @Entity
@Table(name = "node_infos") @Table(name = "node_infos")
class PersistentNodeInfo( class PersistentNodeInfo(

View File

@ -4,9 +4,7 @@ import net.corda.core.contracts.*
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import org.hibernate.annotations.Type import org.hibernate.annotations.Type
import java.util.* import java.util.*
import javax.persistence.Column import javax.persistence.*
import javax.persistence.ElementCollection
import javax.persistence.MappedSuperclass
/** /**
* JPA representation of the common schema entities * JPA representation of the common schema entities
@ -18,6 +16,8 @@ object CommonSchema
*/ */
object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, version = 1, mappedTypes = emptyList()) { object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, version = 1, mappedTypes = emptyList()) {
override val migrationResource = "common.changelog-master"
@MappedSuperclass @MappedSuperclass
open class LinearState( open class LinearState(
/** [ContractState] attributes */ /** [ContractState] attributes */
@ -25,6 +25,9 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers
/** X500Name of participant parties **/ /** X500Name of participant parties **/
@ElementCollection @ElementCollection
@Column(name = "participants") @Column(name = "participants")
@CollectionTable(name="state_participants",joinColumns = arrayOf(
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
var participants: MutableSet<AbstractParty>? = null, var participants: MutableSet<AbstractParty>? = null,
/** /**
@ -34,6 +37,7 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers
var externalId: String?, var externalId: String?,
@Column(name = "uuid", nullable = false) @Column(name = "uuid", nullable = false)
@Type(type = "uuid-char")
var uuid: UUID var uuid: UUID
) : PersistentState() { ) : PersistentState() {
@ -50,6 +54,9 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers
/** X500Name of participant parties **/ /** X500Name of participant parties **/
@ElementCollection @ElementCollection
@Column(name = "participants") @Column(name = "participants")
@CollectionTable(name="state_participants",joinColumns = arrayOf(
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
var participants: MutableSet<AbstractParty>? = null, var participants: MutableSet<AbstractParty>? = null,
/** [OwnableState] attributes */ /** [OwnableState] attributes */

View File

@ -38,9 +38,16 @@ interface QueryableState : ContractState {
* @param mappedTypes The JPA entity classes that the ORM layer needs to be configure with for this schema. * @param mappedTypes The JPA entity classes that the ORM layer needs to be configure with for this schema.
*/ */
open class MappedSchema(schemaFamily: Class<*>, open class MappedSchema(schemaFamily: Class<*>,
val version: Int, val version: Int,
val mappedTypes: Iterable<Class<*>>) { val mappedTypes: Iterable<Class<*>>) {
val name: String = schemaFamily.name val name: String = schemaFamily.name
/**
* Points to a classpath resource containing the database changes for the [mappedTypes]
*/
protected open val migrationResource: String? = null
internal fun getMigrationResource(): String = migrationResource!!
override fun toString(): String = "${this.javaClass.simpleName}(name=$name, version=$version)" override fun toString(): String = "${this.javaClass.simpleName}(name=$name, version=$version)"
} }
//DOCEND MappedSchema //DOCEND MappedSchema
@ -69,4 +76,6 @@ data class PersistentStateRef(
/** /**
* Marker interface to denote a persistable Corda state entity that will always have a transaction id and index * Marker interface to denote a persistable Corda state entity that will always have a transaction id and index
*/ */
interface StatePersistable interface StatePersistable
fun getMigrationResource(schema: MappedSchema): String = schema.getMigrationResource()

View File

@ -49,7 +49,7 @@ class ContractUpgradeFlowTest {
@Before @Before
fun setup() { fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", "net.corda.core.flows")) mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", "net.corda.core.flows", "net.corda.finance.schemas"))
aliceNode = mockNet.createPartyNode(ALICE_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME)
bobNode = mockNet.createPartyNode(BOB_NAME) bobNode = mockNet.createPartyNode(BOB_NAME)
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity

View File

@ -144,3 +144,94 @@ which is then referenced within a custom flow:
:start-after: DOCSTART TopupIssuer :start-after: DOCSTART TopupIssuer
:end-before: DOCEND TopupIssuer :end-before: DOCEND TopupIssuer
Database Migration
==================
As a database migration tool, we use the open source library liquibase <http://www.liquibase.org/>.
If migration is enabled, the database state is checked (and updated) during node startup. (After deploying a new version of the code that contains database migrations, they are executed at that point).
Possible database changes range from schema changes to data changes.
Liquibase will create a table called ``DATABASECHANGELOG``, that will store useful information about each change ( like timestamp, description, user, md5 hash so it can't be changed, etc)
We can also "tag" the database at each release to make rollback easier.
Database changes are maintained in several xml files per ``MappedSchema``, so that only migrations corresponding to the nodes configured schemas are run.
For example, on the node-info schema, if there are any database changes for release 12, the changes will be added to a new file called: ``node-info.changelog-v12.xml`` which has to be included in ``node-info.changelog-master.xml``.
Example:
--------
Let's suppose that at some point, at version 12, there is a need to add a new column: ``contentSize`` to the ``DBAttachment`` entity.
This means we have to:
- In the source code, add the ``contentSize`` property and map it to a new column.
- create the column in the ``node_attachments`` table.
- Run an update to set the size of all existing attachments, to not break the code that uses the new property
.. code-block:: kotlin
class DBAttachment(
...
@Column(name = "content")
@Lob
var content: ByteArray,
//newly added column
@Column(name = "content_size")
var contentSize: Int,
...
)
The ``DBAttachment`` entity is included in the ``NodeServicesV1`` schema, so we create a file ``node-services.changelog-v12.xml`` with this changeset:
.. code-block:: xml
<changeSet author="developer_name" id="add content_size column">
<addColumn tableName="node_attachments">
<column name="content_size" type="INT"/>
</addColumn>
<update tableName="node_attachments">
<column name="content_size" valueComputed="length(content)"/>
</update>
<rollback>
<dropColumn tableName="node_attachments" columnName="content_size"/>
</rollback>
</changeSet>
And include it in `node-services.changelog-master.xml`:
.. code-block:: xml
<databaseChangeLog>
<!--the original schema-->
<include file="migration/node-services.changelog-init.xml"/>
<!--migrations from previous releases-->
<include file="migration/node-services.changelog-v4.xml"/>
<include file="migration/node-services.changelog-v7.xml"/>
<!--added now-->
<include file="migration/node-services.changelog-v12.xml"/>
</databaseChangeLog>
By adding the rollback script, we give users the option to revert to an older version of the software.
An easy way to manage the db version is to tag it on every release (or on every release that has migrations)
<http://www.liquibase.org/documentation/changes/tag_database.html>
Usage:
------
Configurations:
- To enable migration at startup, set:
- database.runMigration = true // true by default
Command line arguments:
- To export the migration to a file use `—just-generate-database-migration outputSqlFile`. This will generate the delta from the last release, and will output the resulting sql into the outputSqlFile. It will not write to the db. It will not start the node! ( default value for `outputSqlFile` is a `.sql` file with the current date )
- To run the migration without starting the node: `--just-run-db-migration`

View File

@ -6,6 +6,13 @@ from the previous milestone release.
UNRELEASED UNRELEASED
---------- ----------
* Integrate database migration tool: http://www.liquibase.org/ :
* The migration files are split per ``MappedSchemas``. (added new property: migrationResource used to point to the resource file containing the db changes corresponding to the JPA entities)
* config flag ``database.initialiseSchema`` was renamed to: ``database.runMigration`` (if true then the migration is run during startup just before hibernate is initialised.)
* config flag: ``database.serverNameTablePrefix`` was removed as we no longer need table prefixes
* New command line argument: “—just-generate-database-migration outputSqlFile”: This will generate the delta from the last release, and will output the resulting sql into the outputSqlFile. It will not write to the db. It will not start the node!
* New command line argument: “--just-run-db-migration”: This will only run the db migration. It will not start the node!
* Exporting additional JMX metrics (artemis, hibernate statistics) and loading Jolokia agent at JVM startup when using * Exporting additional JMX metrics (artemis, hibernate statistics) and loading Jolokia agent at JVM startup when using
DriverDSL and/or cordformation node runner. DriverDSL and/or cordformation node runner.

View File

@ -70,7 +70,6 @@ path to the node's base directory.
:database: Database configuration: :database: Database configuration:
:serverNameTablePrefix: Prefix string to apply to all the database tables. The default is no prefix.
:transactionIsolationLevel: Transaction isolation level as defined by the ``TRANSACTION_`` constants in :transactionIsolationLevel: Transaction isolation level as defined by the ``TRANSACTION_`` constants in
``java.sql.Connection``, but without the "TRANSACTION_" prefix. Defaults to REPEATABLE_READ. ``java.sql.Connection``, but without the "TRANSACTION_" prefix. Defaults to REPEATABLE_READ.
:exportHibernateJMXStatistics: Whether to export Hibernate JMX statistics (caution: expensive run-time overhead) :exportHibernateJMXStatistics: Whether to export Hibernate JMX statistics (caution: expensive run-time overhead)
@ -81,13 +80,13 @@ path to the node's base directory.
:database: This section is used to configure JDBC and Hibernate related properties: :database: This section is used to configure JDBC and Hibernate related properties:
:serverNameTablePrefix: Prefix string to apply to all the database tables. The default is no prefix.
:transactionIsolationLevel: Transaction isolation level as defined by the ``TRANSACTION_`` constants in :transactionIsolationLevel: Transaction isolation level as defined by the ``TRANSACTION_`` constants in
``java.sql.Connection``, but without the "TRANSACTION_" prefix. Defaults to REPEATABLE_READ. ``java.sql.Connection``, but without the "TRANSACTION_" prefix. Defaults to REPEATABLE_READ.
:exportHibernateJMXStatistics: Whether to export Hibernate JMX statistics (caution: expensive run-time overhead) :exportHibernateJMXStatistics: Whether to export Hibernate JMX statistics (caution: expensive run-time overhead)
:runMigration: Boolean on whether to run the database migration scripts. Defaults to true.
:schema: (optional) some database providers require a schema name when generating DDL and SQL statements. :schema: (optional) some database providers require a schema name when generating DDL and SQL statements.
(the value is passed to Hibernate property 'hibernate.hbm2ddl.auto'). (the value is passed to Hibernate property 'hibernate.hbm2ddl.auto').

View File

@ -19,7 +19,11 @@ object CashSchema
* at the time of writing. * at the time of writing.
*/ */
@CordaSerializable @CordaSerializable
object CashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) { object CashSchemaV1 : MappedSchema(
schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) {
override val migrationResource = "cash.changelog-master"
@Entity @Entity
@Table(name = "contract_cash_states", @Table(name = "contract_cash_states",
indexes = arrayOf(Index(name = "ccy_code_idx", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_idx", columnList = "ccy_code"),

View File

@ -22,7 +22,11 @@ object CommercialPaperSchema
* as it stood at the time of writing. * as it stood at the time of writing.
*/ */
@CordaSerializable @CordaSerializable
object CommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) { object CommercialPaperSchemaV1 : MappedSchema(
schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) {
override val migrationResource = "commercial-paper.changelog-master"
@Entity @Entity
@Table(name = "cp_states", @Table(name = "cp_states",
indexes = arrayOf(Index(name = "ccy_code_index", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_index", columnList = "ccy_code"),

View File

@ -0,0 +1,31 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<changeSet author="tudormalene (generated)" id="1511451595465-2">
<createTable tableName="contract_cash_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="issuer_key_hash" type="VARCHAR(130)"/>
<column name="issuer_ref" type="varbinary(512)"/>
<column name="owner_name" type="VARCHAR(255)"/>
<column name="pennies" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-28">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="contract_cash_states_pkey" tableName="contract_cash_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-51">
<createIndex indexName="ccy_code_idx" tableName="contract_cash_states">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-57">
<createIndex indexName="pennies_idx" tableName="contract_cash_states">
<column name="pennies"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<include file="migration/cash.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,39 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-3">
<createTable tableName="cp_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="face_value" type="BIGINT"/>
<column name="face_value_issuer_key_hash" type="VARCHAR(130)"/>
<column name="face_value_issuer_ref" type="varbinary(512)"/>
<column name="issuance_key_hash" type="VARCHAR(130)"/>
<column name="issuance_ref" type="varbinary(255)"/>
<column name="maturity_instant" type="timestamp"/>
<column name="owner_key_hash" type="VARCHAR(130)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-29">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="cp_states_pkey" tableName="cp_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-52">
<createIndex indexName="ccy_code_index" tableName="cp_states">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-54">
<createIndex indexName="face_value_index" tableName="cp_states">
<column name="face_value"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-56">
<createIndex indexName="maturity_index" tableName="cp_states">
<column name="maturity_instant"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/commercial-paper.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -261,14 +261,14 @@ class CommercialPaperTestsGeneric {
private lateinit var aliceVaultService: VaultService private lateinit var aliceVaultService: VaultService
private lateinit var alicesVault: Vault<ContractState> private lateinit var alicesVault: Vault<ContractState>
private val notaryServices = MockServices(rigorousMock(), MEGA_CORP.name, dummyNotary.key) private val notaryServices = MockServices(rigorousMock(), MEGA_CORP.name, dummyNotary.key)
private val issuerServices = MockServices(listOf("net.corda.finance.contracts"), rigorousMock(), MEGA_CORP.name, dummyCashIssuer.key) private val issuerServices = MockServices(listOf("net.corda.finance.contracts", "net.corda.finance.schemas"), rigorousMock(), MEGA_CORP.name, dummyCashIssuer.key)
private lateinit var moveTX: SignedTransaction private lateinit var moveTX: SignedTransaction
@Test @Test
fun `issue move and then redeem`() { fun `issue move and then redeem`() {
val aliceDatabaseAndServices = makeTestDatabaseAndMockServices( val aliceDatabaseAndServices = makeTestDatabaseAndMockServices(
listOf(ALICE_KEY), listOf(ALICE_KEY),
makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)),
listOf("net.corda.finance.contracts"), listOf("net.corda.finance.contracts", "net.corda.finance.schemas"),
MEGA_CORP.name) MEGA_CORP.name)
val databaseAlice = aliceDatabaseAndServices.first val databaseAlice = aliceDatabaseAndServices.first
aliceServices = aliceDatabaseAndServices.second aliceServices = aliceDatabaseAndServices.second
@ -281,7 +281,7 @@ class CommercialPaperTestsGeneric {
val bigCorpDatabaseAndServices = makeTestDatabaseAndMockServices( val bigCorpDatabaseAndServices = makeTestDatabaseAndMockServices(
listOf(BIG_CORP_KEY), listOf(BIG_CORP_KEY),
makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)),
listOf("net.corda.finance.contracts"), listOf("net.corda.finance.contracts", "net.corda.finance.schemas"),
MEGA_CORP.name) MEGA_CORP.name)
val databaseBigCorp = bigCorpDatabaseAndServices.first val databaseBigCorp = bigCorpDatabaseAndServices.first
bigCorpServices = bigCorpDatabaseAndServices.second bigCorpServices = bigCorpDatabaseAndServices.second

View File

@ -93,15 +93,15 @@ class CashTests {
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(NodeVaultService::class) LogHelper.setLevel(NodeVaultService::class)
megaCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY) megaCorpServices = MockServices(listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"), rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY)
miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock<IdentityServiceInternal>().also { miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"), rigorousMock<IdentityServiceInternal>().also {
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MINI_CORP.name }) doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MINI_CORP.name })
}, MINI_CORP.name, MINI_CORP_KEY) }, MINI_CORP.name, MINI_CORP_KEY)
val notaryServices = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val notaryServices = MockServices(listOf("net.corda.finance.contracts.asset"), rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
val databaseAndServices = makeTestDatabaseAndMockServices( val databaseAndServices = makeTestDatabaseAndMockServices(
listOf(generateKeyPair()), listOf(generateKeyPair()),
makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)),
listOf("net.corda.finance.contracts.asset"), listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"),
CordaX500Name("Me", "London", "GB")) CordaX500Name("Me", "London", "GB"))
database = databaseAndServices.first database = databaseAndServices.first
ourServices = databaseAndServices.second ourServices = databaseAndServices.second

View File

@ -8,9 +8,9 @@ import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.QueryableState import net.corda.core.schemas.QueryableState
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.finance.schemas.SampleCashSchemaV1 import net.corda.finance.sampleschemas.SampleCashSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV2 import net.corda.finance.sampleschemas.SampleCashSchemaV2
import net.corda.finance.schemas.SampleCashSchemaV3 import net.corda.finance.sampleschemas.SampleCashSchemaV3
import net.corda.finance.utils.sumCash import net.corda.finance.utils.sumCash
import net.corda.finance.utils.sumCashOrNull import net.corda.finance.utils.sumCashOrNull
import net.corda.finance.utils.sumCashOrZero import net.corda.finance.utils.sumCashOrZero

View File

@ -17,7 +17,7 @@ import org.junit.Test
import java.util.Collections.nCopies import java.util.Collections.nCopies
class CashSelectionH2ImplTest { class CashSelectionH2ImplTest {
private val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance")) private val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance", "net.corda.core.schemas", "net.corda.finance.sampleschemas"))
@After @After
fun cleanUp() { fun cleanUp() {

View File

@ -29,7 +29,7 @@ class CashExitFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("net.corda.finance.contracts.asset")) cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME)
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity

View File

@ -26,7 +26,9 @@ class CashIssueFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts.asset")) mockNet = MockNetwork(
servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME)
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity

View File

@ -31,7 +31,7 @@ class CashPaymentFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts.asset")) mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME)
aliceNode = mockNet.createPartyNode(ALICE_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME)

View File

@ -1,4 +1,4 @@
package net.corda.finance.schemas package net.corda.finance.sampleschemas
import net.corda.core.contracts.MAX_ISSUER_REF_SIZE import net.corda.core.contracts.MAX_ISSUER_REF_SIZE
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
@ -20,8 +20,11 @@ object CashSchema
* at the time of writing. * at the time of writing.
*/ */
object SampleCashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) { object SampleCashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) {
override val migrationResource = "sample-cash-v1.changelog-init"
@Entity @Entity
@Table(name = "contract_cash_states", @Table(name = "contract_cash_states_v1",
indexes = arrayOf(Index(name = "ccy_code_idx", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_idx", columnList = "ccy_code"),
Index(name = "pennies_idx", columnList = "pennies"))) Index(name = "pennies_idx", columnList = "pennies")))
class PersistentCashState( class PersistentCashState(

View File

@ -1,4 +1,4 @@
package net.corda.finance.schemas package net.corda.finance.sampleschemas
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.schemas.CommonSchemaV1 import net.corda.core.schemas.CommonSchemaV1
@ -15,6 +15,9 @@ import javax.persistence.Table
*/ */
object SampleCashSchemaV2 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 2, object SampleCashSchemaV2 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 2,
mappedTypes = listOf(PersistentCashState::class.java)) { mappedTypes = listOf(PersistentCashState::class.java)) {
override val migrationResource = "sample-cash-v2.changelog-init"
@Entity @Entity
@Table(name = "cash_states_v2", @Table(name = "cash_states_v2",
indexes = arrayOf(Index(name = "ccy_code_idx2", columnList = "ccy_code"))) indexes = arrayOf(Index(name = "ccy_code_idx2", columnList = "ccy_code")))

View File

@ -1,14 +1,11 @@
package net.corda.finance.schemas package net.corda.finance.sampleschemas
import net.corda.core.contracts.MAX_ISSUER_REF_SIZE import net.corda.core.contracts.MAX_ISSUER_REF_SIZE
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import org.hibernate.annotations.Type import org.hibernate.annotations.Type
import javax.persistence.Column import javax.persistence.*
import javax.persistence.ElementCollection
import javax.persistence.Entity
import javax.persistence.Table
/** /**
* First version of a cash contract ORM schema that maps all fields of the [Cash] contract state as it stood * First version of a cash contract ORM schema that maps all fields of the [Cash] contract state as it stood
@ -16,6 +13,9 @@ import javax.persistence.Table
*/ */
object SampleCashSchemaV3 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 3, object SampleCashSchemaV3 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 3,
mappedTypes = listOf(PersistentCashState::class.java)) { mappedTypes = listOf(PersistentCashState::class.java)) {
override val migrationResource = "sample-cash-v3.changelog-init"
@Entity @Entity
@Table(name = "cash_states_v3") @Table(name = "cash_states_v3")
class PersistentCashState( class PersistentCashState(
@ -23,6 +23,9 @@ object SampleCashSchemaV3 : MappedSchema(schemaFamily = CashSchema.javaClass, ve
/** X500Name of participant parties **/ /** X500Name of participant parties **/
@ElementCollection @ElementCollection
@CollectionTable(name="state_participants", joinColumns = arrayOf(
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
var participants: MutableSet<AbstractParty>? = null, var participants: MutableSet<AbstractParty>? = null,
/** X500Name of owner party **/ /** X500Name of owner party **/

View File

@ -1,4 +1,4 @@
package net.corda.finance.schemas package net.corda.finance.sampleschemas
import net.corda.core.contracts.MAX_ISSUER_REF_SIZE import net.corda.core.contracts.MAX_ISSUER_REF_SIZE
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
@ -21,8 +21,11 @@ object CommercialPaperSchema
* as it stood at the time of writing. * as it stood at the time of writing.
*/ */
object SampleCommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) { object SampleCommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) {
override val migrationResource = "sample-cp-v1.changelog-init"
@Entity @Entity
@Table(name = "cp_states", @Table(name = "cp_states_v1",
indexes = arrayOf(Index(name = "ccy_code_index", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_index", columnList = "ccy_code"),
Index(name = "maturity_index", columnList = "maturity_instant"), Index(name = "maturity_index", columnList = "maturity_instant"),
Index(name = "face_value_index", columnList = "face_value"))) Index(name = "face_value_index", columnList = "face_value")))

View File

@ -1,4 +1,4 @@
package net.corda.finance.schemas package net.corda.finance.sampleschemas
import net.corda.core.contracts.MAX_ISSUER_REF_SIZE import net.corda.core.contracts.MAX_ISSUER_REF_SIZE
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
@ -19,6 +19,9 @@ import javax.persistence.Table
*/ */
object SampleCommercialPaperSchemaV2 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, object SampleCommercialPaperSchemaV2 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1,
mappedTypes = listOf(PersistentCommercialPaperState::class.java)) { mappedTypes = listOf(PersistentCommercialPaperState::class.java)) {
override val migrationResource = "sample-cp-v2.changelog-init"
@Entity @Entity
@Table(name = "cp_states_v2", @Table(name = "cp_states_v2",
indexes = arrayOf(Index(name = "ccy_code_index2", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_index2", columnList = "ccy_code"),

View File

@ -0,0 +1,35 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-2">
<createTable tableName="contract_cash_states_v1">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="issuer_key_hash" type="VARCHAR(130)"/>
<column name="issuer_ref" type="varbinary(512)"/>
<column name="owner_key_hash" type="VARCHAR(130)"/>
<column name="pennies" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-28">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="contract_cash_states_v1_pkey"
tableName="contract_cash_states_v1"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-51">
<createIndex indexName="ccy_code_v1_idx" tableName="contract_cash_states_v1">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-57">
<createIndex indexName="pennies_v1_idx" tableName="contract_cash_states_v1">
<column name="pennies"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,31 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1512743551377-1">
<createTable tableName="cash_states_v2">
<column name="output_index" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="issuer_name" type="VARCHAR(255)"/>
<column name="issuer_ref" type="VARBINARY(512)"/>
<column name="owner_name" type="VARCHAR(255)"/>
<column name="quantity" type="BIGINT(19)"/>
<column name="ccy_code" type="VARCHAR(3)"/>
</createTable>
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="CONSTRAINT_D"
tableName="cash_states_v2"/>
<createIndex indexName="ccy_code_idx2" tableName="cash_states_v2">
<column name="ccy_code"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,27 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1512743551377-2">
<createTable tableName="cash_states_v3">
<column name="output_index" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="issuer_name" type="VARCHAR(255)"/>
<column name="issuer_ref" type="VARBINARY(512)"/>
<column name="owner_name" type="VARCHAR(255)"/>
<column name="pennies" type="BIGINT(19)"/>
</createTable>
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="CONSTRAINT_DC"
tableName="cash_states_v3"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,29 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-3">
<createTable tableName="cp_states_v1">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="face_value" type="BIGINT"/>
<column name="face_value_issuer_key_hash" type="VARCHAR(130)"/>
<column name="face_value_issuer_ref" type="varbinary(512)"/>
<column name="issuance_key_hash" type="VARCHAR(130)"/>
<column name="issuance_ref" type="varbinary(255)"/>
<column name="maturity_instant" type="timestamp"/>
<column name="owner_key_hash" type="VARCHAR(130)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-29">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="cp_states_v1_pkey"
tableName="cp_states_v1"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,32 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1512743551377-4">
<createTable tableName="cp_states_v2">
<column name="output_index" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="issuer_name" type="VARCHAR(255)"/>
<column name="issuer_ref" type="VARBINARY(512)"/>
<column name="owner_name" type="VARCHAR(255)"/>
<column name="quantity" type="BIGINT(19)"/>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="face_value_issuer_key_hash" type="VARCHAR(130)"/>
<column name="face_value_issuer_ref" type="VARBINARY(512)"/>
<column name="maturity_instant" type="TIMESTAMP"/>
</createTable>
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="CONSTRAINT_5"
tableName="cp_states_v2"/>
<createIndex indexName="ccy_code_index2" tableName="cp_states_v2">
<column name="ccy_code"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -190,4 +190,4 @@ private fun makeTestDataSourceProperties(): Properties {
return props return props
} }
internal fun makeNotInitialisingTestDatabaseProperties() = DatabaseConfig(initialiseSchema = false) internal fun makeNotInitialisingTestDatabaseProperties() = DatabaseConfig(runMigration = false)

View File

@ -7,6 +7,7 @@ import net.corda.core.schemas.MappedSchema
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.nodeapi.internal.persistence.DatabaseTransaction import net.corda.nodeapi.internal.persistence.DatabaseTransaction
import net.corda.nodeapi.internal.persistence.SchemaMigration
import java.util.* import java.util.*
import javax.persistence.LockModeType import javax.persistence.LockModeType
import javax.persistence.criteria.CriteriaBuilder import javax.persistence.criteria.CriteriaBuilder
@ -35,7 +36,13 @@ fun configureDatabase(dataSourceProperties: Properties,
databaseConfig: DatabaseConfig = DatabaseConfig()): CordaPersistence { databaseConfig: DatabaseConfig = DatabaseConfig()): CordaPersistence {
val config = HikariConfig(dataSourceProperties) val config = HikariConfig(dataSourceProperties)
val dataSource = HikariDataSource(config) val dataSource = HikariDataSource(config)
return CordaPersistence(dataSource, databaseConfig, setOf(NetworkManagementSchemaServices.SchemaV1), emptyList())
val schemas = setOf(NetworkManagementSchemaServices.SchemaV1)
if (databaseConfig.runMigration) {
SchemaMigration(schemas, dataSource).runMigration()
}
return CordaPersistence(dataSource, databaseConfig, schemas, emptyList())
} }
sealed class NetworkManagementSchemaServices { sealed class NetworkManagementSchemaServices {
@ -45,5 +52,7 @@ sealed class NetworkManagementSchemaServices {
CertificateDataEntity::class.java, CertificateDataEntity::class.java,
NodeInfoEntity::class.java, NodeInfoEntity::class.java,
NetworkParametersEntity::class.java, NetworkParametersEntity::class.java,
NetworkMapEntity::class.java)) NetworkMapEntity::class.java)) {
override val migrationResource = "network-manager.changelog-master"
}
} }

View File

@ -0,0 +1,176 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1513267683777-1">
<createSequence sequenceName="HIBERNATE_SEQUENCE"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-2">
<createTable tableName="certificatesigningrequestentity_modifiedby">
<column name="certificatesigningrequestentity_request_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="modified_by" type="VARCHAR(512)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-3">
<createTable tableName="certificatesigningrequestentity_modifiedby_aud">
<column name="REV" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="certificatesigningrequestentity_request_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="modified_by" type="VARCHAR(512)">
<constraints nullable="false"/>
</column>
<column name="revtype" type="TINYINT(3)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-4">
<createTable tableName="certificate_data">
<column name="ID" type="BIGINT(19)">
<constraints nullable="false"/>
</column>
<column name="certificate_path_bytes" type="BLOB"/>
<column name="certificate_status" type="INT(10)"/>
<column name="public_key_hash" type="VARCHAR(64)"/>
<column name="certificate_signing_request" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-5">
<createTable tableName="certificate_signing_request">
<column name="request_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="legal_name" type="VARCHAR(256)">
<constraints nullable="false"/>
</column>
<column name="modified_at" type="TIMESTAMP">
<constraints nullable="false"/>
</column>
<column name="remark" type="VARCHAR(256)"/>
<column name="request_bytes" type="BLOB">
<constraints nullable="false"/>
</column>
<column name="status" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-6">
<createTable tableName="certificate_signing_request_aud">
<column name="request_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="rev" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="revtype" type="TINYINT(3)"/>
<column name="modified_at" type="TIMESTAMP"/>
<column name="remark" type="VARCHAR(256)"/>
<column name="status" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-7">
<createTable tableName="network_map">
<column name="version" type="BIGINT(19)">
<constraints nullable="false"/>
</column>
<column name="certificate" type="BLOB"/>
<column name="serialized_network_map" type="BLOB"/>
<column name="signature" type="BLOB"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-8">
<createTable tableName="network_parameters">
<column name="version" type="BIGINT(19)">
<constraints nullable="false"/>
</column>
<column name="bytes" type="BLOB"/>
<column name="hash" type="VARCHAR(64)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-9">
<createTable tableName="node_info">
<column name="node_info_hash" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="node_info_bytes" type="BLOB"/>
<column name="signature_bytes" type="BLOB"/>
<column name="signature_public_key_algorithm" type="CLOB"/>
<column name="signature_public_key_bytes" type="BLOB"/>
<column name="certificate_signing_request" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-10">
<createTable tableName="revinfo">
<column autoIncrement="true" name="rev" type="INT(10)">
<constraints primaryKey="true" primaryKeyName="CONSTRAINT_6"/>
</column>
<column name="revtstmp" type="BIGINT(19)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-11">
<addPrimaryKey columnNames="version" constraintName="CONSTRAINT_3" tableName="network_parameters"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-12">
<addPrimaryKey columnNames="id" constraintName="CONSTRAINT_7" tableName="certificate_data"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-13">
<addPrimaryKey columnNames="rev, certificatesigningrequestentity_request_id, modified_by" constraintName="CONSTRAINT_B" tableName="certificatesigningrequestentity_modifiedby_aud"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-14">
<addPrimaryKey columnNames="request_id, rev" constraintName="CONSTRAINT_C" tableName="certificate_signing_request_aud"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-15">
<addPrimaryKey columnNames="node_info_hash" constraintName="CONSTRAINT_C3" tableName="node_info"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-16">
<addPrimaryKey columnNames="version" constraintName="CONSTRAINT_CB" tableName="network_map"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-17">
<addPrimaryKey columnNames="request_id" constraintName="CONSTRAINT_D" tableName="certificate_signing_request"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-18">
<addUniqueConstraint columnNames="hash" constraintName="UK_3XJ82Q6C0LT4D7XV085CUUX4Q" tableName="network_parameters"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-19">
<addUniqueConstraint columnNames="certificate_signing_request" constraintName="UK_4MJ3D7DDYMYV6OA2284VWDFHV" tableName="certificate_data"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-20">
<addUniqueConstraint columnNames="certificate_signing_request" constraintName="UK_P37OS0TPLQ2ER2TM9JSDTF1CL" tableName="node_info"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-21">
<createIndex indexName="FK5G5CAGCRX7SIU8LWTAVIRUNXD_INDEX_C" tableName="certificate_signing_request_aud">
<column name="rev"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-22">
<createIndex indexName="FKLFW2KLKDPLYDROVIBVEOMF9PU_INDEX_C" tableName="certificatesigningrequestentity_modifiedby">
<column name="certificatesigningrequestentity_request_id"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-23">
<createIndex indexName="IDX_PUB_KEY_HASH" tableName="certificate_data">
<column name="public_key_hash"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-24">
<addForeignKeyConstraint baseColumnNames="rev" baseTableName="certificate_signing_request_aud" constraintName="FK5G5CAGCRX7SIU8LWTAVIRUNXD" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="rev" referencedTableName="revinfo"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-25">
<addForeignKeyConstraint baseColumnNames="rev" baseTableName="certificatesigningrequestentity_modifiedby_aud" constraintName="FKCNMAJ1J6TO8D5GBY6N1Q3CK9C" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="rev" referencedTableName="revinfo"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-26">
<addForeignKeyConstraint baseColumnNames="certificatesigningrequestentity_request_id" baseTableName="certificatesigningrequestentity_modifiedby" constraintName="FKLFW2KLKDPLYDROVIBVEOMF9PU" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-27">
<addForeignKeyConstraint baseColumnNames="certificate_signing_request" baseTableName="certificate_data" constraintName="FKLQK11Q68B23W062SH0CLNQKLY" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1513267683777-28">
<addForeignKeyConstraint baseColumnNames="certificate_signing_request" baseTableName="node_info" constraintName="FKOLO0DB56L1GS6AAY86TBNIXRH" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="request_id" referencedTableName="certificate_signing_request"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<include file="migration/network-manager.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -34,6 +34,9 @@ dependencies {
// For AMQP serialisation. // For AMQP serialisation.
compile "org.apache.qpid:proton-j:0.21.0" compile "org.apache.qpid:proton-j:0.21.0"
// For db migration
compile "org.liquibase:liquibase-core:$liquibase_version"
// Unit testing helpers. // Unit testing helpers.
testCompile "junit:junit:$junit_version" testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:$assertj_version" testCompile "org.assertj:assertj-core:$assertj_version"

View File

@ -18,8 +18,7 @@ const val NODE_DATABASE_PREFIX = "node_"
// This class forms part of the node config and so any changes to it must be handled with care // This class forms part of the node config and so any changes to it must be handled with care
data class DatabaseConfig( data class DatabaseConfig(
val initialiseSchema: Boolean = true, val runMigration: Boolean = true,
val serverNameTablePrefix: String = "",
val transactionIsolationLevel: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ, val transactionIsolationLevel: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ,
val schema: String? = null, val schema: String? = null,
val exportHibernateJMXStatistics: Boolean = false val exportHibernateJMXStatistics: Boolean = false
@ -47,6 +46,7 @@ class CordaPersistence(
) : Closeable { ) : Closeable {
val defaultIsolationLevel = databaseConfig.transactionIsolationLevel val defaultIsolationLevel = databaseConfig.transactionIsolationLevel
val hibernateConfig: HibernateConfiguration by lazy { val hibernateConfig: HibernateConfiguration by lazy {
transaction { transaction {
HibernateConfiguration(schemas, databaseConfig, attributeConverters) HibernateConfiguration(schemas, databaseConfig, attributeConverters)
} }

View File

@ -47,25 +47,17 @@ class HibernateConfiguration(
logger.info("Creating session factory for schemas: $schemas") logger.info("Creating session factory for schemas: $schemas")
val serviceRegistry = BootstrapServiceRegistryBuilder().build() val serviceRegistry = BootstrapServiceRegistryBuilder().build()
val metadataSources = MetadataSources(serviceRegistry) val metadataSources = MetadataSources(serviceRegistry)
// We set a connection provider as the auto schema generation requires it. The auto schema generation will not
// necessarily remain and would likely be replaced by something like Liquibase. For now it is very convenient though.
// TODO: replace auto schema generation as it isn't intended for production use, according to Hibernate docs.
val config = Configuration(metadataSources).setProperty("hibernate.connection.provider_class", NodeDatabaseConnectionProvider::class.java.name)
.setProperty("hibernate.hbm2ddl.auto", if (databaseConfig.initialiseSchema) "update" else "validate")
.setProperty("hibernate.format_sql", "true")
.setProperty("hibernate.connection.isolation", databaseConfig.transactionIsolationLevel.jdbcValue.toString())
if (databaseConfig.schema != null) { val config = Configuration(metadataSources).setProperty("hibernate.connection.provider_class", NodeDatabaseConnectionProvider::class.java.name)
// This property helps 'hibernate.hbm2ddl.auto' to work properly when many schemas have similar table names. .setProperty("hibernate.hbm2ddl.auto", "validate")
config.setProperty("hibernate.default_schema", databaseConfig.schema) .setProperty("hibernate.connection.isolation", databaseConfig.transactionIsolationLevel.jdbcValue.toString())
}
schemas.forEach { schema -> schemas.forEach { schema ->
// TODO: require mechanism to set schemaOptions (databaseSchema, tablePrefix) which are not global to session // TODO: require mechanism to set schemaOptions (databaseSchema, tablePrefix) which are not global to session
schema.mappedTypes.forEach { config.addAnnotatedClass(it) } schema.mappedTypes.forEach { config.addAnnotatedClass(it) }
} }
val sessionFactory = buildSessionFactory(config, metadataSources, databaseConfig.serverNameTablePrefix) val sessionFactory = buildSessionFactory(config, metadataSources)
logger.info("Created session factory for schemas: $schemas") logger.info("Created session factory for schemas: $schemas")
// export Hibernate JMX statistics // export Hibernate JMX statistics
@ -92,15 +84,9 @@ class HibernateConfiguration(
} }
} }
private fun buildSessionFactory(config: Configuration, metadataSources: MetadataSources, tablePrefix: String): SessionFactory { private fun buildSessionFactory(config: Configuration, metadataSources: MetadataSources): SessionFactory {
config.standardServiceRegistryBuilder.applySettings(config.properties) config.standardServiceRegistryBuilder.applySettings(config.properties)
val metadata = metadataSources.getMetadataBuilder(config.standardServiceRegistryBuilder.build()).run { val metadata = metadataSources.getMetadataBuilder(config.standardServiceRegistryBuilder.build()).run {
applyPhysicalNamingStrategy(object : PhysicalNamingStrategyStandardImpl() {
override fun toPhysicalTableName(name: Identifier?, context: JdbcEnvironment?): Identifier {
val default = super.toPhysicalTableName(name, context)
return Identifier.toIdentifier(tablePrefix + default.text, default.isQuoted)
}
})
// register custom converters // register custom converters
attributeConverters.forEach { applyAttributeConverter(it) } attributeConverters.forEach { applyAttributeConverter(it) }
// Register a tweaked version of `org.hibernate.type.MaterializedBlobType` that truncates logged messages. // Register a tweaked version of `org.hibernate.type.MaterializedBlobType` that truncates logged messages.

View File

@ -0,0 +1,84 @@
package net.corda.nodeapi.internal.persistence
import com.fasterxml.jackson.databind.ObjectMapper
import liquibase.Contexts
import liquibase.Liquibase
import liquibase.database.Database
import liquibase.database.DatabaseFactory
import liquibase.database.core.MSSQLDatabase
import liquibase.database.jvm.JdbcConnection
import liquibase.resource.ClassLoaderResourceAccessor
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.getMigrationResource
import java.io.*
import javax.sql.DataSource
private const val MIGRATION_PREFIX = "migration"
class SchemaMigration(val schemas: Set<MappedSchema>, val dataSource: DataSource) {
fun generateMigrationScript(outputFile: File) = doRunMigration(PrintWriter(outputFile))
fun runMigration() = doRunMigration()
private fun doRunMigration(outputWriter: Writer? = null) {
// virtual file name of the changelog that includes all schemas
val dynamicInclude = "master.changelog.json"
dataSource.connection.use { connection ->
//create a resourse accessor that aggregates the changelogs included in the schemas into one dynamic stream
val customResourceAccessor = object : ClassLoaderResourceAccessor() {
override fun getResourcesAsStream(path: String): Set<InputStream> {
if (path == dynamicInclude) {
//collect all changelog file referenced in the included schemas
val changelogList = schemas.map { mappedSchema ->
getMigrationResource(mappedSchema).let {
"${MIGRATION_PREFIX}/${it}.xml"
}
}
//create a map in liquibase format including all migration files
val includeAllFiles = mapOf("databaseChangeLog" to changelogList.map { file -> mapOf("include" to mapOf("file" to file)) })
// transform it to json
val includeAllFilesJson = ObjectMapper().writeValueAsBytes(includeAllFiles)
//return the json as a stream
return setOf(ByteArrayInputStream(includeAllFilesJson))
}
return super.getResourcesAsStream(path)?.take(1)?.toSet() ?: emptySet()
}
}
val liquibase = Liquibase(dynamicInclude, customResourceAccessor, getLiquibaseDatabase(JdbcConnection(connection)))
if (outputWriter != null) {
liquibase.update(Contexts(), outputWriter)
} else {
liquibase.update(Contexts())
}
}
}
private fun getLiquibaseDatabase(conn: JdbcConnection): Database {
// the standard MSSQLDatabase in liquibase does not support sequences for Ms Azure
// this class just overrides that behaviour
class AzureDatabase(conn: JdbcConnection) : MSSQLDatabase() {
init {
this.connection = conn
}
override fun getShortName(): String = "azure"
override fun supportsSequences(): Boolean = true
}
val liquibaseDbImplementation = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(conn)
return if (liquibaseDbImplementation is MSSQLDatabase) AzureDatabase(conn) else liquibaseDbImplementation
}
}

View File

@ -11,6 +11,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.POUNDS import net.corda.finance.POUNDS
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.flows.CashPaymentFlow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.config.User
@ -45,7 +46,7 @@ class DistributedServiceTests : IntegrationTest() {
) )
driver( driver(
extraCordappPackagesToScan = listOf("net.corda.finance.contracts"), extraCordappPackagesToScan = listOf("net.corda.finance.contracts", "net.corda.finance.schemas"),
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = listOf(testUser), cluster = ClusterSpec.Raft(clusterSize = 3)))) notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = listOf(testUser), cluster = ClusterSpec.Raft(clusterSize = 3))))
{ {
alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(testUser)).getOrThrow() alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(testUser)).getOrThrow()

View File

@ -138,6 +138,8 @@ object MessageSchemaV1 : MappedSchema(
version = 1, version = 1,
mappedTypes = listOf(PersistentMessage::class.java)) { mappedTypes = listOf(PersistentMessage::class.java)) {
override val migrationResource = "message-schema.changelog-init"
@Entity @Entity
@Table(name = "messages") @Table(name = "messages")
class PersistentMessage( class PersistentMessage(

View File

@ -0,0 +1,20 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1512743551377-1">
<createTable tableName="messages">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="message_by" type="VARCHAR(255)"/>
<column name="message_value" type="VARCHAR(255)"/>
</createTable>
</changeSet>
</databaseChangeLog>

View File

@ -10,6 +10,8 @@ import org.slf4j.event.Level
import java.io.PrintStream import java.io.PrintStream
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.text.SimpleDateFormat
import java.util.*
// NOTE: Do not use any logger in this class as args parsing is done before the logger is setup. // NOTE: Do not use any logger in this class as args parsing is done before the logger is setup.
class ArgsParser { class ArgsParser {
@ -34,8 +36,13 @@ class ArgsParser {
private val noLocalShellArg = optionParser.accepts("no-local-shell", "Do not start the embedded shell locally.") private val noLocalShellArg = optionParser.accepts("no-local-shell", "Do not start the embedded shell locally.")
private val isRegistrationArg = optionParser.accepts("initial-registration", "Start initial node registration with Corda network to obtain certificate from the permissioning server.") private val isRegistrationArg = optionParser.accepts("initial-registration", "Start initial node registration with Corda network to obtain certificate from the permissioning server.")
private val isVersionArg = optionParser.accepts("version", "Print the version and exit") private val isVersionArg = optionParser.accepts("version", "Print the version and exit")
private val justRunDbMigrationArg = optionParser.accepts("just-run-db-migration",
"This will only run the db migration. It will not start the node!")
private val justGenerateNodeInfoArg = optionParser.accepts("just-generate-node-info", private val justGenerateNodeInfoArg = optionParser.accepts("just-generate-node-info",
"Perform the node start-up task necessary to generate its nodeInfo, save it to disk, then quit") "Perform the node start-up task necessary to generate its nodeInfo, save it to disk, then quit")
private val justGenerateDatabaseMigrationArg = optionParser
.accepts("just-generate-database-migration", "Generate the database migration in the specified output file, and then quit.")
.withOptionalArg()
private val bootstrapRaftClusterArg = optionParser.accepts("bootstrap-raft-cluster", "Bootstraps Raft cluster. The node forms a single node cluster (ignoring otherwise configured peer addresses), acting as a seed for other nodes to join the cluster.") private val bootstrapRaftClusterArg = optionParser.accepts("bootstrap-raft-cluster", "Bootstraps Raft cluster. The node forms a single node cluster (ignoring otherwise configured peer addresses), acting as a seed for other nodes to join the cluster.")
private val helpArg = optionParser.accepts("help").forHelp() private val helpArg = optionParser.accepts("help").forHelp()
@ -54,9 +61,14 @@ class ArgsParser {
val noLocalShell = optionSet.has(noLocalShellArg) val noLocalShell = optionSet.has(noLocalShellArg)
val sshdServer = optionSet.has(sshdServerArg) val sshdServer = optionSet.has(sshdServerArg)
val justGenerateNodeInfo = optionSet.has(justGenerateNodeInfoArg) val justGenerateNodeInfo = optionSet.has(justGenerateNodeInfoArg)
val justRunDbMigration = optionSet.has(justRunDbMigrationArg)
val generateDatabaseMigrationToFile = if (optionSet.has(justGenerateDatabaseMigrationArg))
Pair(true, optionSet.valueOf(justGenerateDatabaseMigrationArg) ?: "migration${SimpleDateFormat("yyyyMMddHHmmss").format(Date())}.sql")
else
Pair(false, null)
val bootstrapRaftCluster = optionSet.has(bootstrapRaftClusterArg) val bootstrapRaftCluster = optionSet.has(bootstrapRaftClusterArg)
return CmdLineOptions(baseDirectory, configFile, help, loggingLevel, logToConsole, isRegistration, isVersion, return CmdLineOptions(baseDirectory, configFile, help, loggingLevel, logToConsole, isRegistration, isVersion,
noLocalShell, sshdServer, justGenerateNodeInfo, bootstrapRaftCluster) noLocalShell, sshdServer, justGenerateNodeInfo, justRunDbMigration, generateDatabaseMigrationToFile, bootstrapRaftCluster)
} }
fun printHelp(sink: PrintStream) = optionParser.printHelpOn(sink) fun printHelp(sink: PrintStream) = optionParser.printHelpOn(sink)
@ -72,6 +84,8 @@ data class CmdLineOptions(val baseDirectory: Path,
val noLocalShell: Boolean, val noLocalShell: Boolean,
val sshdServer: Boolean, val sshdServer: Boolean,
val justGenerateNodeInfo: Boolean, val justGenerateNodeInfo: Boolean,
val justRunDbMigration: Boolean,
val generateDatabaseMigrationToFile: Pair<Boolean, String?>,
val bootstrapRaftCluster: Boolean) { val bootstrapRaftCluster: Boolean) {
fun loadConfig(): NodeConfiguration { fun loadConfig(): NodeConfiguration {
val config = ConfigHelper.loadConfig(baseDirectory, configFile).parseAsNodeConfiguration() val config = ConfigHelper.loadConfig(baseDirectory, configFile).parseAsNodeConfiguration()

View File

@ -59,6 +59,7 @@ import net.corda.node.services.vault.VaultSoftLockManager
import net.corda.node.shell.InteractiveShell import net.corda.node.shell.InteractiveShell
import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.AffinityExecutor
import net.corda.nodeapi.internal.NetworkParameters import net.corda.nodeapi.internal.NetworkParameters
import net.corda.nodeapi.internal.persistence.SchemaMigration
import net.corda.nodeapi.internal.crypto.* import net.corda.nodeapi.internal.crypto.*
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
@ -68,6 +69,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry
import org.slf4j.Logger import org.slf4j.Logger
import rx.Observable import rx.Observable
import rx.Scheduler import rx.Scheduler
import java.io.File
import java.io.IOException import java.io.IOException
import java.lang.management.ManagementFactory import java.lang.management.ManagementFactory
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
@ -195,6 +197,18 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
} }
} }
fun generateDatabaseSchema(outputFile: String) {
HikariDataSource(HikariConfig(configuration.dataSourceProperties)).use { dataSource ->
SchemaMigration(cordappLoader.cordappSchemas, dataSource).generateMigrationScript(File(outputFile))
}
}
fun runDbMigration() {
HikariDataSource(HikariConfig(configuration.dataSourceProperties)).use { dataSource ->
SchemaMigration(cordappLoader.cordappSchemas, dataSource).runMigration()
}
}
open fun start(): StartedNode<AbstractNode> { open fun start(): StartedNode<AbstractNode> {
check(started == null) { "Node has already been started" } check(started == null) { "Node has already been started" }
log.info("Node starting up ...") log.info("Node starting up ...")
@ -829,6 +843,12 @@ fun configureDatabase(dataSourceProperties: Properties,
JavaTypeDescriptorRegistry.INSTANCE.addDescriptor(AbstractPartyDescriptor(identityService)) JavaTypeDescriptorRegistry.INSTANCE.addDescriptor(AbstractPartyDescriptor(identityService))
val config = HikariConfig(dataSourceProperties) val config = HikariConfig(dataSourceProperties)
val dataSource = HikariDataSource(config) val dataSource = HikariDataSource(config)
val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(identityService)) val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(identityService))
if(databaseConfig.runMigration){
SchemaMigration(schemaService.schemaOptions.keys, dataSource).runMigration()
}
return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters) return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters)
} }

View File

@ -120,6 +120,14 @@ open class NodeStartup(val args: Array<String>) {
node.generateNodeInfo() node.generateNodeInfo()
return return
} }
if (cmdlineOptions.justRunDbMigration) {
node.runDbMigration()
return
}
if (cmdlineOptions.generateDatabaseMigrationToFile.first) {
node.generateDatabaseSchema(cmdlineOptions.generateDatabaseMigrationToFile.second!!)
return
}
val startedNode = node.start() val startedNode = node.start()
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name }) Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name })
startedNode.internals.nodeReadyFuture.thenMatch({ startedNode.internals.nodeReadyFuture.thenMatch({

View File

@ -120,7 +120,7 @@ data class NodeConfigurationImpl(
// TODO See TODO above. Rename this to nodeInfoPollingFrequency and make it of type Duration // TODO See TODO above. Rename this to nodeInfoPollingFrequency and make it of type Duration
override val additionalNodeInfoPollingFrequencyMsec: Long = 5.seconds.toMillis(), override val additionalNodeInfoPollingFrequencyMsec: Long = 5.seconds.toMillis(),
override val sshd: SSHDConfiguration? = null, override val sshd: SSHDConfiguration? = null,
override val database: DatabaseConfig = DatabaseConfig(initialiseSchema = devMode, exportHibernateJMXStatistics = devMode) override val database: DatabaseConfig = DatabaseConfig(exportHibernateJMXStatistics = devMode)
) : NodeConfiguration { ) : NodeConfiguration {
override val exportJMXto: String get() = "http" override val exportJMXto: String get() = "http"

View File

@ -51,7 +51,9 @@ class NodeSchemaService(extraSchemas: Set<MappedSchema> = emptySet()) : SchemaSe
PersistentIdentityService.PersistentIdentityNames::class.java, PersistentIdentityService.PersistentIdentityNames::class.java,
ContractUpgradeServiceImpl.DBContractUpgrade::class.java, ContractUpgradeServiceImpl.DBContractUpgrade::class.java,
RunOnceService.MutualExclusion::class.java RunOnceService.MutualExclusion::class.java
)) )){
override val migrationResource = "node-services.changelog-master"
}
// Required schemas are those used by internal Corda services // Required schemas are those used by internal Corda services
// For example, cash is used by the vault for coin selection (but will be extracted as a standalone CorDapp in future) // For example, cash is used by the vault for coin selection (but will be extracted as a standalone CorDapp in future)

View File

@ -27,6 +27,9 @@ object VaultSchema
@CordaSerializable @CordaSerializable
object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, version = 1, object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, version = 1,
mappedTypes = listOf(VaultStates::class.java, VaultLinearStates::class.java, VaultFungibleStates::class.java, VaultTxnNote::class.java)) { mappedTypes = listOf(VaultStates::class.java, VaultLinearStates::class.java, VaultFungibleStates::class.java, VaultTxnNote::class.java)) {
override val migrationResource = "vault-schema.changelog-master"
@Entity @Entity
@Table(name = "vault_states", @Table(name = "vault_states",
indexes = arrayOf(Index(name = "state_status_idx", columnList = "state_status"), indexes = arrayOf(Index(name = "state_status_idx", columnList = "state_status"),

View File

@ -0,0 +1,29 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-1" dbms="mssql">
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-1.2" dbms="azure">
<createSequence sequenceName="hibernate_sequence" minValue="1"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-1.1" dbms="h2">
<createSequence sequenceName="hibernate_sequence"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="create state_participants table">
<createTable tableName="state_participants">
<column name="output_index" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="participants" type="VARCHAR(255)"/>
</createTable>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,9 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/common.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,72 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-4">
<createTable tableName="node_link_nodeinfo_party">
<column name="node_info_id" type="INT">
<constraints nullable="false"/>
</column>
<column name="party_name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-10">
<createTable tableName="node_info_hosts">
<column name="host" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="port" type="INT">
<constraints nullable="false"/>
</column>
<column name="node_info_id" type="INT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-11">
<createTable tableName="node_info_party_cert">
<column name="party_name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="ismain" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="owning_key_hash" type="VARCHAR(130)"/>
<column name="party_cert_binary" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-12">
<createTable tableName="node_infos">
<column name="node_info_id" type="INT">
<constraints nullable="false"/>
</column>
<column name="node_info_hash" type="VARCHAR(64)"/>
<column name="platform_version" type="INT"/>
<column name="serial" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-35">
<addPrimaryKey columnNames="host, port" constraintName="node_info_hosts_pkey" tableName="node_info_hosts"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-36">
<addPrimaryKey columnNames="party_name" constraintName="node_info_party_cert_pkey"
tableName="node_info_party_cert"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-37">
<addPrimaryKey columnNames="node_info_id" constraintName="node_infos_pkey" tableName="node_infos"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-62">
<addForeignKeyConstraint baseColumnNames="node_info_id" baseTableName="node_link_nodeinfo_party"
constraintName="fk544l9wsec35ph7hxrtwfd2lws" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="node_info_id" referencedTableName="node_infos"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-63">
<addForeignKeyConstraint baseColumnNames="node_info_id" baseTableName="node_info_hosts"
constraintName="fk5ie46htdrkftmwe6rpwrnp0mp" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="node_info_id" referencedTableName="node_infos"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,9 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/node-info.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,213 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-5">
<createTable tableName="node_attachments">
<column name="att_id" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="content" type="blob"/>
<column name="filename" type="VARCHAR(255)"/>
<column name="insertion_date" type="timestamp">
<constraints nullable="false"/>
</column>
<column name="uploader" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-6">
<createTable tableName="node_bft_committed_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="consuming_input_index" type="INT"/>
<column name="consuming_transaction_id" type="VARCHAR(255)"/>
<column name="requesting_party_name" type="VARCHAR(255)"/>
<column name="requesting_party_key" type="varbinary(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-7">
<createTable tableName="node_checkpoints">
<column name="checkpoint_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="checkpoint_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-8">
<createTable tableName="node_contract_upgrades">
<column name="state_ref" type="VARCHAR(96)">
<constraints nullable="false"/>
</column>
<column name="contract_class_name" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-9">
<createTable tableName="node_identities">
<column name="pk_hash" type="VARCHAR(130)">
<constraints nullable="false"/>
</column>
<column name="identity_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-13">
<createTable tableName="node_message_ids">
<column name="message_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="insertion_time" type="timestamp"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-14">
<createTable tableName="node_message_retry">
<column name="message_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="message" type="blob"/>
<column name="recipients" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-15">
<createTable tableName="node_named_identities">
<column name="name" type="VARCHAR(128)">
<constraints nullable="false"/>
</column>
<column name="pk_hash" type="VARCHAR(130)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-16">
<createTable tableName="node_notary_commit_log">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="consuming_input_index" type="INT"/>
<column name="consuming_transaction_id" type="VARCHAR(255)"/>
<column name="requesting_party_name" type="VARCHAR(255)"/>
<column name="requesting_party_key" type="varbinary(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-17">
<createTable tableName="node_our_key_pairs">
<column name="public_key_hash" type="VARCHAR(130)">
<constraints nullable="false"/>
</column>
<column name="private_key" type="blob"/>
<column name="public_key" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-18">
<createTable tableName="node_raft_committed_states">
<column name="id" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="state_index" type="BIGINT"/>
<column name="state_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-19">
<createTable tableName="node_scheduled_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="scheduled_at" type="timestamp">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-20">
<createTable tableName="node_transaction_mappings">
<column name="tx_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="state_machine_run_id" type="VARCHAR(36)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-21">
<createTable tableName="node_transactions">
<column name="tx_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="transaction_value" type="blob"/>
</createTable>
</changeSet>
<changeSet author="tudormalene" id="create mutual exclusion">
<createTable tableName="node_mutual_exclusion">
<column name="mutual_exclusion_id" type="CHAR(255)">
<constraints nullable="false"/>
</column>
<column name="MACHINE_NAME" type="VARCHAR(255)"/>
<column name="PID" type="VARCHAR(255)"/>
<column name="MUTUAL_EXCLUSION_TIMESTAMP" type="timestamp"/>
</createTable>
<addPrimaryKey columnNames="mutual_exclusion_id" constraintName="node_mutual_exclusion_pkey" tableName="node_mutual_exclusion"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-30">
<addPrimaryKey columnNames="att_id" constraintName="node_attachments_pkey" tableName="node_attachments"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-31">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_bft_committed_states_pkey"
tableName="node_bft_committed_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-32">
<addPrimaryKey columnNames="checkpoint_id" constraintName="node_checkpoints_pkey" tableName="node_checkpoints"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-33">
<addPrimaryKey columnNames="state_ref" constraintName="node_contract_upgrades_pkey"
tableName="node_contract_upgrades"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-34">
<addPrimaryKey columnNames="pk_hash" constraintName="node_identities_pkey" tableName="node_identities"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-38">
<addPrimaryKey columnNames="message_id" constraintName="node_message_ids_pkey" tableName="node_message_ids"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-39">
<addPrimaryKey columnNames="message_id" constraintName="node_message_retry_pkey"
tableName="node_message_retry"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-40">
<addPrimaryKey columnNames="name" constraintName="node_named_identities_pkey"
tableName="node_named_identities"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-41">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_notary_commit_log_pkey"
tableName="node_notary_commit_log"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-42">
<addPrimaryKey columnNames="public_key_hash" constraintName="node_our_key_pairs_pkey"
tableName="node_our_key_pairs"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-43">
<addPrimaryKey columnNames="id" constraintName="node_raft_committed_states_pkey"
tableName="node_raft_committed_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-44">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="node_scheduled_states_pkey"
tableName="node_scheduled_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-45">
<addPrimaryKey columnNames="tx_id" constraintName="node_transaction_mappings_pkey"
tableName="node_transaction_mappings"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-46">
<addPrimaryKey columnNames="tx_id" constraintName="node_transactions_pkey" tableName="node_transactions"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-61">
<addForeignKeyConstraint baseColumnNames="party_name" baseTableName="node_link_nodeinfo_party"
constraintName="fk1ua3h6nwwfji0mn23c5d1xx8e" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="party_name" referencedTableName="node_info_party_cert"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,9 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/node-services.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,140 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-22">
<createTable tableName="vault_fungible_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="issuer_name" type="VARCHAR(255)"/>
<column name="issuer_ref" type="varbinary(512)"/>
<column name="owner_name" type="VARCHAR(255)"/>
<column name="quantity" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-23">
<createTable tableName="vault_fungible_states_parts">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="participants" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-24">
<createTable tableName="vault_linear_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="external_id" type="VARCHAR(255)"/>
<column name="uuid" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-25">
<createTable tableName="vault_linear_states_parts">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="participants" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-26">
<createTable tableName="vault_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="consumed_timestamp" type="timestamp"/>
<column name="contract_state_class_name" type="VARCHAR(255)"/>
<column name="lock_id" type="VARCHAR(255)"/>
<column name="lock_timestamp" type="timestamp"/>
<column name="notary_name" type="VARCHAR(255)"/>
<column name="recorded_timestamp" type="timestamp"/>
<column name="state_status" type="INT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-27">
<createTable tableName="vault_transaction_notes">
<column name="seq_no" type="INT">
<constraints nullable="false"/>
</column>
<column name="note" type="VARCHAR(255)"/>
<column name="transaction_id" type="VARCHAR(64)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-47">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="vault_fungible_states_pkey"
tableName="vault_fungible_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-48">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="vault_linear_states_pkey"
tableName="vault_linear_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-49">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="vault_states_pkey"
tableName="vault_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-50">
<addPrimaryKey columnNames="seq_no" constraintName="vault_transaction_notes_pkey"
tableName="vault_transaction_notes"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-53">
<createIndex indexName="external_id_index" tableName="vault_linear_states">
<column name="external_id"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-55">
<createIndex indexName="lock_id_idx" tableName="vault_states">
<column name="lock_id"/>
<column name="state_status"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-58">
<createIndex indexName="state_status_idx" tableName="vault_states">
<column name="state_status"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-59">
<createIndex indexName="transaction_id_index" tableName="vault_transaction_notes">
<column name="transaction_id"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-60">
<createIndex indexName="uuid_index" tableName="vault_linear_states">
<column name="uuid"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-64">
<addForeignKeyConstraint baseColumnNames="output_index,transaction_id"
baseTableName="vault_fungible_states_parts"
constraintName="fkchmfeq1ldqnoq9idv9ogxauqm" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="output_index,transaction_id"
referencedTableName="vault_fungible_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-65">
<addForeignKeyConstraint baseColumnNames="output_index,transaction_id" baseTableName="vault_linear_states_parts"
constraintName="fkhafsv733d0bo9j1tg352koq3y" deferrable="false"
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
referencedColumnNames="output_index,transaction_id"
referencedTableName="vault_linear_states"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,9 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/vault-schema.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -27,6 +27,7 @@ import net.corda.testing.TestIdentity;
import net.corda.testing.contracts.DummyLinearContract; import net.corda.testing.contracts.DummyLinearContract;
import net.corda.testing.contracts.VaultFiller; import net.corda.testing.contracts.VaultFiller;
import net.corda.testing.node.MockServices; import net.corda.testing.node.MockServices;
import net.corda.testing.schemas.DummyLinearStateSchemaV1;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
@ -69,7 +70,11 @@ public class VaultQueryJavaTests {
@Before @Before
public void setUp() throws CertificateException, InvalidAlgorithmParameterException { public void setUp() throws CertificateException, InvalidAlgorithmParameterException {
List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName()); List<String> cordappPackages = Arrays.asList(
"net.corda.testing.contracts",
"net.corda.finance.contracts.asset",
CashSchemaV1.class.getPackage().getName(),
DummyLinearStateSchemaV1.class.getPackage().getName());
IdentityServiceInternal identitySvc = makeTestIdentityService(Arrays.asList(MEGA_CORP.getIdentity(), DUMMY_CASH_ISSUER_INFO.getIdentity(), DUMMY_NOTARY.getIdentity())); IdentityServiceInternal identitySvc = makeTestIdentityService(Arrays.asList(MEGA_CORP.getIdentity(), DUMMY_CASH_ISSUER_INFO.getIdentity(), DUMMY_NOTARY.getIdentity()));
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices( Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(
Arrays.asList(MEGA_CORP.getKey(), DUMMY_NOTARY.getKey()), Arrays.asList(MEGA_CORP.getKey(), DUMMY_NOTARY.getKey()),

View File

@ -25,7 +25,10 @@ class ArgsParserTest {
noLocalShell = false, noLocalShell = false,
sshdServer = false, sshdServer = false,
justGenerateNodeInfo = false, justGenerateNodeInfo = false,
bootstrapRaftCluster = false)) justRunDbMigration = false,
bootstrapRaftCluster = false,
generateDatabaseMigrationToFile = Pair(false, null)
))
} }
@Test @Test

View File

@ -76,7 +76,7 @@ class CordaRPCOpsImplTest {
@Before @Before
fun setup() { fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.finance.contracts.asset")) mockNet = MockNetwork(cordappPackages = listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"))
aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME)) aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
rpc = SecureCordaRPCOps(aliceNode.services, aliceNode.smm, aliceNode.database, aliceNode.services) rpc = SecureCordaRPCOps(aliceNode.services, aliceNode.smm, aliceNode.database, aliceNode.services)
CURRENT_RPC_CONTEXT.set(RpcAuthContext(InvocationContext.rpc(testActor()), buildSubject("TEST_USER", emptySet()))) CURRENT_RPC_CONTEXT.set(RpcAuthContext(InvocationContext.rpc(testActor()), buildSubject("TEST_USER", emptySet())))

View File

@ -68,7 +68,7 @@ import kotlin.test.assertTrue
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class TwoPartyTradeFlowTests(private val anonymous: Boolean) { class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
companion object { companion object {
private val cordappPackages = listOf("net.corda.finance.contracts") private val cordappPackages = listOf("net.corda.finance.contracts", "net.corda.finance.schemas")
@JvmStatic @JvmStatic
@Parameterized.Parameters(name = "Anonymous = {0}") @Parameterized.Parameters(name = "Anonymous = {0}")
fun data(): Collection<Boolean> = listOf(true, false) fun data(): Collection<Boolean> = listOf(true, false)

View File

@ -25,8 +25,8 @@ import net.corda.finance.SWISS_FRANCS
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.contracts.asset.DummyFungibleContract import net.corda.finance.contracts.asset.DummyFungibleContract
import net.corda.finance.schemas.CashSchemaV1 import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV2 import net.corda.finance.sampleschemas.SampleCashSchemaV2
import net.corda.finance.schemas.SampleCashSchemaV3 import net.corda.finance.sampleschemas.SampleCashSchemaV3
import net.corda.finance.utils.sumCash import net.corda.finance.utils.sumCash
import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
@ -40,6 +40,7 @@ import net.corda.testing.*
import net.corda.testing.contracts.* import net.corda.testing.contracts.*
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.schemas.DummyDealStateSchemaV1
import net.corda.testing.schemas.DummyLinearStateSchemaV1 import net.corda.testing.schemas.DummyLinearStateSchemaV1
import net.corda.testing.schemas.DummyLinearStateSchemaV2 import net.corda.testing.schemas.DummyLinearStateSchemaV2
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
@ -105,7 +106,7 @@ class HibernateConfigurationTest {
doReturn(it.party).whenever(mock).wellKnownPartyFromX500Name(it.name) doReturn(it.party).whenever(mock).wellKnownPartyFromX500Name(it.name)
} }
} }
val schemaService = NodeSchemaService() val schemaService = NodeSchemaService(extraSchemas = setOf(CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3, DummyLinearStateSchemaV1, DummyLinearStateSchemaV2, DummyDealStateSchemaV1 ))
database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService, schemaService) database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService, schemaService)
database.transaction { database.transaction {
hibernateConfig = database.hibernateConfig hibernateConfig = database.hibernateConfig

View File

@ -8,6 +8,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
import net.corda.core.schemas.CommonSchemaV1
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.QueryableState import net.corda.core.schemas.QueryableState
@ -55,7 +56,9 @@ class HibernateObserverTests {
val testSchema = TestSchema val testSchema = TestSchema
val rawUpdatesPublisher = PublishSubject.create<Vault.Update<ContractState>>() val rawUpdatesPublisher = PublishSubject.create<Vault.Update<ContractState>>()
val schemaService = object : SchemaService { val schemaService = object : SchemaService {
override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = emptyMap() override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = mapOf(
CommonSchemaV1 to SchemaService.SchemaOptions(),
testSchema to SchemaService.SchemaOptions())
override fun selectSchemas(state: ContractState): Iterable<MappedSchema> = setOf(testSchema) override fun selectSchemas(state: ContractState): Iterable<MappedSchema> = setOf(testSchema)

View File

@ -72,8 +72,11 @@ class NodeSchemaServiceTest {
class SchemaFamily class SchemaFamily
object TestSchema : MappedSchema(SchemaFamily::class.java, 1, setOf(Parent::class.java, Child::class.java)) { object TestSchema : MappedSchema(SchemaFamily::class.java, 1, setOf(Parent::class.java, Child::class.java)) {
override val migrationResource = "test.changelog-init"
@Entity @Entity
@Table(name = "Parents") @Table(name = "parents")
class Parent : PersistentState() { class Parent : PersistentState() {
@OneToMany(fetch = FetchType.LAZY) @OneToMany(fetch = FetchType.LAZY)
@JoinColumns(JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), JoinColumn(name = "output_index", referencedColumnName = "output_index")) @JoinColumns(JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), JoinColumn(name = "output_index", referencedColumnName = "output_index"))
@ -84,7 +87,7 @@ object TestSchema : MappedSchema(SchemaFamily::class.java, 1, setOf(Parent::clas
@Suppress("unused") @Suppress("unused")
@Entity @Entity
@Table(name = "Children") @Table(name = "children")
class Child { class Child {
@Id @Id
@GeneratedValue @GeneratedValue

View File

@ -88,7 +88,7 @@ class DistributedImmutableMapTests {
private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> { private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> {
val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build() val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build()
val address = Address(myAddress.host, myAddress.port) val address = Address(myAddress.host, myAddress.port)
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(serverNameTablePrefix = "PORT_${myAddress.port}_"), rigorousMock()) val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
databases.add(database) databases.add(database)
val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) } val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) }

View File

@ -21,7 +21,7 @@ import net.corda.finance.contracts.asset.Cash
import net.corda.finance.schemas.CashSchemaV1 import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.CashSchemaV1.PersistentCashState import net.corda.finance.schemas.CashSchemaV1.PersistentCashState
import net.corda.finance.schemas.CommercialPaperSchemaV1 import net.corda.finance.schemas.CommercialPaperSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV3 import net.corda.finance.sampleschemas.SampleCashSchemaV3
import net.corda.node.internal.configureDatabase import net.corda.node.internal.configureDatabase
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
@ -30,6 +30,7 @@ import net.corda.testing.contracts.*
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.makeTestIdentityService import net.corda.testing.node.makeTestIdentityService
import net.corda.testing.schemas.DummyDealStateSchemaV1
import net.corda.testing.schemas.DummyLinearStateSchemaV1 import net.corda.testing.schemas.DummyLinearStateSchemaV1
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
@ -91,7 +92,8 @@ open class VaultQueryTests {
"net.corda.testing.contracts", "net.corda.testing.contracts",
"net.corda.finance.contracts", "net.corda.finance.contracts",
CashSchemaV1::class.packageName, CashSchemaV1::class.packageName,
DummyLinearStateSchemaV1::class.packageName) DummyLinearStateSchemaV1::class.packageName,
DummyDealStateSchemaV1::class.packageName)
private lateinit var services: MockServices private lateinit var services: MockServices
private lateinit var vaultFiller: VaultFiller private lateinit var vaultFiller: VaultFiller
private lateinit var vaultFillerCashNotary: VaultFiller private lateinit var vaultFillerCashNotary: VaultFiller

View File

@ -25,6 +25,7 @@ import net.corda.testing.contracts.*
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.makeTestIdentityService import net.corda.testing.node.makeTestIdentityService
import net.corda.testing.schemas.DummyLinearStateSchemaV1
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After import org.junit.After
@ -39,7 +40,8 @@ import kotlin.test.fail
class VaultWithCashTest { class VaultWithCashTest {
private companion object { private companion object {
val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName) private val cordappPackages = listOf(
"net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName, DummyLinearStateSchemaV1::class.packageName)
val BOB = TestIdentity(BOB_NAME, 80).party val BOB = TestIdentity(BOB_NAME, 80).party
val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10) val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1) val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1)

View File

@ -0,0 +1,29 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1512743551377-11">
<createTable tableName="parents">
<column name="output_index" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="CONSTRAINT_F" tableName="parents"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1512743551377-18">
<createTable tableName="children">
<column name="child_id" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="output_index" type="INT(10)"/>
<column name="transaction_id" type="VARCHAR(64)"/>
</createTable>
<addPrimaryKey columnNames="child_id" constraintName="CONSTRAINT_9" tableName="children"/>
</changeSet>
</databaseChangeLog>

View File

@ -18,6 +18,7 @@ import net.corda.core.transactions.TransactionBuilder
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.schemas.CommercialPaperSchemaV1 import com.r3.corda.enterprise.perftestcordapp.schemas.CommercialPaperSchemaV1
import com.r3.corda.enterprise.perftestcordapp.utils.sumCashBy import com.r3.corda.enterprise.perftestcordapp.utils.sumCashBy
import net.corda.core.crypto.toStringShort
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*
@ -76,13 +77,13 @@ class CommercialPaper : Contract {
override fun generateMappedObject(schema: MappedSchema): PersistentState { override fun generateMappedObject(schema: MappedSchema): PersistentState {
return when (schema) { return when (schema) {
is CommercialPaperSchemaV1 -> CommercialPaperSchemaV1.PersistentCommercialPaperState( is CommercialPaperSchemaV1 -> CommercialPaperSchemaV1.PersistentCommercialPaperState(
issuanceParty = this.issuance.party.owningKey.toBase58String(), issuancePartyHash = this.issuance.party.owningKey.toStringShort(),
issuanceRef = this.issuance.reference.bytes, issuanceRef = this.issuance.reference.bytes,
owner = this.owner.owningKey.toBase58String(), ownerHash = this.owner.owningKey.toStringShort(),
maturity = this.maturityDate, maturity = this.maturityDate,
faceValue = this.faceValue.quantity, faceValue = this.faceValue.quantity,
currency = this.faceValue.token.product.currencyCode, currency = this.faceValue.token.product.currencyCode,
faceValueIssuerParty = this.faceValue.token.issuer.party.owningKey.toBase58String(), faceValueIssuerPartyHash = this.faceValue.token.issuer.party.owningKey.toStringShort(),
faceValueIssuerRef = this.faceValue.token.issuer.reference.bytes faceValueIssuerRef = this.faceValue.token.issuer.reference.bytes
) )
/** Additional schema mappings would be added here (eg. CommercialPaperV2, ...) */ /** Additional schema mappings would be added here (eg. CommercialPaperV2, ...) */

View File

@ -56,9 +56,9 @@ class CashSelectionH2Impl : AbstractCashSelection() {
if (notary != null) if (notary != null)
psSelectJoin.setString(++pIndex, notary.name.toString()) psSelectJoin.setString(++pIndex, notary.name.toString())
if (onlyFromIssuerParties.isNotEmpty()) if (onlyFromIssuerParties.isNotEmpty())
psSelectJoin.setObject(++pIndex, onlyFromIssuerParties.map { it.owningKey.toStringShort() as Any }.toTypedArray()) psSelectJoin.setObject(++pIndex, onlyFromIssuerParties.map { it.owningKey.toStringShort() as Any}.toTypedArray() )
if (withIssuerRefs.isNotEmpty()) if (withIssuerRefs.isNotEmpty())
psSelectJoin.setObject(++pIndex, withIssuerRefs.map { it.bytes as Any }.toTypedArray()) psSelectJoin.setObject(++pIndex, withIssuerRefs.map { it.bytes.toHexString() as Any }.toTypedArray())
log.debug { psSelectJoin.toString() } log.debug { psSelectJoin.toString() }
psSelectJoin.executeQuery().use { rs -> psSelectJoin.executeQuery().use { rs ->

View File

@ -21,6 +21,8 @@ object CashSchema
*/ */
@CordaSerializable @CordaSerializable
object CashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) { object CashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java)) {
override val migrationResource = "cash-pt.changelog-master"
@Entity @Entity
@Table(name = "contract_pt_cash_states", @Table(name = "contract_pt_cash_states",
indexes = arrayOf(Index(name = "ccy_code_idx", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_idx", columnList = "ccy_code"),

View File

@ -1,7 +1,11 @@
package com.r3.corda.enterprise.perftestcordapp.schemas package com.r3.corda.enterprise.perftestcordapp.schemas
import net.corda.core.contracts.MAX_ISSUER_REF_SIZE
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
import org.hibernate.annotations.Type
import java.time.Instant import java.time.Instant
import javax.persistence.Column import javax.persistence.Column
import javax.persistence.Entity import javax.persistence.Entity
@ -19,20 +23,23 @@ object CommercialPaperSchema
*/ */
@CordaSerializable @CordaSerializable
object CommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) { object CommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCommercialPaperState::class.java)) {
override val migrationResource = "commercial-paper-pt.changelog-master"
@Entity @Entity
@Table(name = "cp_pt_states", @Table(name = "cp_pt_states",
indexes = arrayOf(Index(name = "ccy_code_index", columnList = "ccy_code"), indexes = arrayOf(Index(name = "ccy_code_index", columnList = "ccy_code"),
Index(name = "maturity_index", columnList = "maturity_instant"), Index(name = "maturity_index", columnList = "maturity_instant"),
Index(name = "face_value_index", columnList = "face_value"))) Index(name = "face_value_index", columnList = "face_value")))
class PersistentCommercialPaperState( class PersistentCommercialPaperState(
@Column(name = "issuance_key") @Column(name = "issuance_key_hash", length = MAX_HASH_HEX_SIZE)
var issuanceParty: String, var issuancePartyHash: String,
@Column(name = "issuance_ref") @Column(name = "issuance_ref")
var issuanceRef: ByteArray, var issuanceRef: ByteArray,
@Column(name = "owner_key") @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE)
var owner: String, var ownerHash: String,
@Column(name = "maturity_instant") @Column(name = "maturity_instant")
var maturity: Instant, var maturity: Instant,
@ -43,10 +50,11 @@ object CommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPaperSche
@Column(name = "ccy_code", length = 3) @Column(name = "ccy_code", length = 3)
var currency: String, var currency: String,
@Column(name = "face_value_issuer_key") @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE)
var faceValueIssuerParty: String, var faceValueIssuerPartyHash: String,
@Column(name = "face_value_issuer_ref") @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE)
@Type(type = "corda-wrapper-binary")
var faceValueIssuerRef: ByteArray var faceValueIssuerRef: ByteArray
) : PersistentState() ) : PersistentState()
} }

View File

@ -0,0 +1,31 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<changeSet author="tudormalene (generated)" id="perf test cash">
<createTable tableName="contract_pt_cash_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="issuer_key_hash" type="VARCHAR(130)"/>
<column name="issuer_ref" type="varbinary(512)"/>
<column name="owner_name" type="VARCHAR(255)"/>
<column name="pennies" type="BIGINT"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-28">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="contract_pt_cash_states_pkey" tableName="contract_pt_cash_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-51">
<createIndex indexName="ccy_pt_code_idx" tableName="contract_pt_cash_states">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-57">
<createIndex indexName="pennies_pt_idx" tableName="contract_pt_cash_states">
<column name="pennies"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd" >
<include file="migration/cash-pt.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -0,0 +1,39 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1511451595465-3">
<createTable tableName="cp_pt_states">
<column name="output_index" type="INT">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="ccy_code" type="VARCHAR(3)"/>
<column name="face_value" type="BIGINT"/>
<column name="face_value_issuer_key_hash" type="VARCHAR(130)"/>
<column name="face_value_issuer_ref" type="varbinary(512)"/>
<column name="issuance_key_hash" type="VARCHAR(130)"/>
<column name="issuance_ref" type="varbinary(255)"/>
<column name="maturity_instant" type="timestamp"/>
<column name="owner_key_hash" type="VARCHAR(130)"/>
</createTable>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-29">
<addPrimaryKey columnNames="output_index, transaction_id" constraintName="cp_pt_states_pkey" tableName="cp_pt_states"/>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-52">
<createIndex indexName="ccy_cp_pt_code_index" tableName="cp_pt_states">
<column name="ccy_code"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-54">
<createIndex indexName="face_value_cp_pt_index" tableName="cp_pt_states">
<column name="face_value"/>
</createIndex>
</changeSet>
<changeSet author="tudormalene (generated)" id="1511451595465-56">
<createIndex indexName="maturity_cp_pt_index" tableName="cp_pt_states">
<column name="maturity_instant"/>
</createIndex>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,6 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<include file="migration/commercial-paper-pt.changelog-init.xml"/>
</databaseChangeLog>

View File

@ -17,7 +17,9 @@ import org.junit.Test
import java.util.Collections.nCopies import java.util.Collections.nCopies
class CashSelectionH2Test { class CashSelectionH2Test {
private val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset")) private val mockNet = MockNetwork(
threadPerNode = true,
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"))
@After @After
fun cleanUp() { fun cleanUp() {

View File

@ -133,13 +133,19 @@ class CashTests {
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(NodeVaultService::class) LogHelper.setLevel(NodeVaultService::class)
megaCorpServices = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY) megaCorpServices = MockServices(
miniCorpServices = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), rigorousMock<IdentityServiceInternal>().also { listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MINI_CORP.name }) rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY)
}, MINI_CORP.name, MINI_CORP_KEY) miniCorpServices = MockServices(
val notaryServices = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
rigorousMock<IdentityServiceInternal>().also {
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MINI_CORP.name })
}, MINI_CORP.name, MINI_CORP_KEY)
val notaryServices = MockServices(
listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
val databaseAndServices = makeTestDatabaseAndMockServices( val databaseAndServices = makeTestDatabaseAndMockServices(
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
initialIdentityName = CordaX500Name(organisation = "Me", locality = "London", country = "GB"), initialIdentityName = CordaX500Name(organisation = "Me", locality = "London", country = "GB"),
keys = listOf(generateKeyPair()), keys = listOf(generateKeyPair()),
identityService = makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY))) identityService = makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)))
@ -247,9 +253,9 @@ class CashTests {
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, output(Cash.PROGRAM_ID,
Cash.State( Cash.State(
amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34),
owner = AnonymousParty(ALICE_PUBKEY))) owner = AnonymousParty(ALICE_PUBKEY)))
command(MINI_CORP_PUBKEY, Cash.Commands.Issue()) command(MINI_CORP_PUBKEY, Cash.Commands.Issue())
this.verifies() this.verifies()
} }
@ -432,9 +438,9 @@ class CashTests {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
input(Cash.PROGRAM_ID, inState) input(Cash.PROGRAM_ID, inState)
input(Cash.PROGRAM_ID, input(Cash.PROGRAM_ID,
inState.copy( inState.copy(
amount = 150.POUNDS `issued by` defaultIssuer, amount = 150.POUNDS `issued by` defaultIssuer,
owner = AnonymousParty(BOB_PUBKEY))) owner = AnonymousParty(BOB_PUBKEY)))
output(Cash.PROGRAM_ID, outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer)) output(Cash.PROGRAM_ID, outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer))
command(ALICE_PUBKEY, Cash.Commands.Move()) command(ALICE_PUBKEY, Cash.Commands.Move())
this `fails with` "the amounts balance" this `fails with` "the amounts balance"
@ -851,16 +857,17 @@ class CashTests {
// Double spend. // Double spend.
@Test @Test
fun chainCashDoubleSpendFailsWith() { fun chainCashDoubleSpendFailsWith() {
val mockService = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), rigorousMock<IdentityServiceInternal>().also { val mockService = MockServices(
listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"), rigorousMock<IdentityServiceInternal>().also {
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY) doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
}, MEGA_CORP.name, MEGA_CORP_KEY) }, MEGA_CORP.name, MEGA_CORP_KEY)
mockService.ledger(DUMMY_NOTARY) { mockService.ledger(DUMMY_NOTARY) {
unverifiedTransaction { unverifiedTransaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
output(Cash.PROGRAM_ID, "MEGA_CORP cash", output(Cash.PROGRAM_ID, "MEGA_CORP cash",
Cash.State( Cash.State(
amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1),
owner = MEGA_CORP)) owner = MEGA_CORP))
} }
transaction { transaction {

View File

@ -29,7 +29,7 @@ class CashExitFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset")) cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME)
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity

View File

@ -31,7 +31,8 @@ class CashIssueAndPaymentFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset")) mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
aliceNode = mockNet.createPartyNode(ALICE_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME)
bankOfCorda = bankOfCordaNode.info.chooseIdentity() bankOfCorda = bankOfCordaNode.info.chooseIdentity()

View File

@ -40,7 +40,7 @@ class CashIssueAndPayNoSelectionTests(private val anonymous: Boolean) {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset")) cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
aliceNode = mockNet.createPartyNode(ALICE_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME)
bankOfCorda = bankOfCordaNode.info.chooseIdentity() bankOfCorda = bankOfCordaNode.info.chooseIdentity()

View File

@ -26,7 +26,9 @@ class CashIssueFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset")) mockNet = MockNetwork(
servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME)
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity

View File

@ -31,7 +31,9 @@ class CashPaymentFlowTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset")) mockNet = MockNetwork(
servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"))
bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) bankOfCordaNode = mockNet.createPartyNode(BOC_NAME)
aliceNode = mockNet.createPartyNode(ALICE_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME)
bankOfCorda = bankOfCordaNode.info.chooseIdentity() bankOfCorda = bankOfCordaNode.info.chooseIdentity()

View File

@ -79,7 +79,8 @@ internal fun CheckpointStorage.checkpoints(): List<SerializedBytes<Checkpoint>>
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class TwoPartyTradeFlowTests(private val anonymous: Boolean) { class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
companion object { companion object {
private val cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts") private val cordappPackages = listOf(
"com.r3.corda.enterprise.perftestcordapp.contracts", "com.r3.corda.enterprise.perftestcordapp.schemas")
@JvmStatic @JvmStatic
@Parameterized.Parameters(name = "Anonymous = {0}") @Parameterized.Parameters(name = "Anonymous = {0}")
fun data(): Collection<Boolean> = listOf(true, false) fun data(): Collection<Boolean> = listOf(true, false)

View File

@ -1,2 +1,3 @@
corda.host=localhost:10006 corda.host=localhost:10006
server.port=10007 server.port=10007
liquibase.enabled=false

View File

@ -1,2 +1,3 @@
corda.host=localhost:10009 corda.host=localhost:10009
server.port=10010 server.port=10010
liquibase.enabled=false

View File

@ -1,2 +1,3 @@
corda.host=localhost:10003 corda.host=localhost:10003
server.port=10004 server.port=10004
liquibase.enabled=false

View File

@ -1,2 +1,3 @@
corda.user=user corda.user=user
corda.password=password corda.password=password
liquibase.enabled=false

View File

@ -8,7 +8,7 @@ import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.context.junit4.SpringRunner
@RunWith(SpringRunner::class) @RunWith(SpringRunner::class)
@SpringBootTest(properties = arrayOf("corda.host=localhost:12345", "corda.user=user", "corda.password=password")) @SpringBootTest(properties = arrayOf("corda.host=localhost:12345", "corda.user=user", "corda.password=password", "liquibase.enabled=false"))
class IrsDemoWebApplicationTests { class IrsDemoWebApplicationTests {
@MockBean @MockBean
lateinit var rpc: CordaRPCOps lateinit var rpc: CordaRPCOps

View File

@ -426,7 +426,7 @@ class DriverDSLImpl(
providedName = nodeNames[0], providedName = nodeNames[0],
rpcUsers = spec.rpcUsers, rpcUsers = spec.rpcUsers,
verifierType = spec.verifierType, verifierType = spec.verifierType,
customOverrides = notaryConfig(clusterAddress) //TODO discrepancy with OS - check if 'serverNameTablePrefix' can be removed in OS customOverrides = notaryConfig(clusterAddress)
) )
// All other nodes will join the cluster // All other nodes will join the cluster
@ -436,7 +436,7 @@ class DriverDSLImpl(
providedName = it, providedName = it,
rpcUsers = spec.rpcUsers, rpcUsers = spec.rpcUsers,
verifierType = spec.verifierType, verifierType = spec.verifierType,
customOverrides = notaryConfig(nodeAddress, clusterAddress) //TODO discrepancy with OS - check if 'serverNameTablePrefix' can be removed in OS customOverrides = notaryConfig(nodeAddress, clusterAddress)
) )
} }

View File

@ -30,6 +30,7 @@ abstract class IntegrationTest {
@JvmStatic @JvmStatic
fun globalSetUp() { fun globalSetUp() {
if (dbProvider.isNotEmpty()) { if (dbProvider.isNotEmpty()) {
runDbScript(dbProvider,"$testDbScriptDir/db-global-cleanup.sql", databaseSchemas)
runDbScript(dbProvider,"$testDbScriptDir/db-global-setup.sql", databaseSchemas) runDbScript(dbProvider,"$testDbScriptDir/db-global-setup.sql", databaseSchemas)
} }
} }

View File

@ -18,6 +18,9 @@ object DummyDealStateSchema
* at the time of writing. * at the time of writing.
*/ */
object DummyDealStateSchemaV1 : MappedSchema(schemaFamily = DummyDealStateSchema.javaClass, version = 1, mappedTypes = listOf(PersistentDummyDealState::class.java)) { object DummyDealStateSchemaV1 : MappedSchema(schemaFamily = DummyDealStateSchema.javaClass, version = 1, mappedTypes = listOf(PersistentDummyDealState::class.java)) {
override val migrationResource = "dummy-deal.changelog-init"
@Entity @Entity
@Table(name = "dummy_deal_states") @Table(name = "dummy_deal_states")
class PersistentDummyDealState( class PersistentDummyDealState(

View File

@ -4,6 +4,7 @@ import net.corda.core.contracts.ContractState
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import org.hibernate.annotations.Type
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*
import javax.persistence.* import javax.persistence.*
@ -18,6 +19,9 @@ object DummyLinearStateSchema
* at the time of writing. * at the time of writing.
*/ */
object DummyLinearStateSchemaV1 : MappedSchema(schemaFamily = DummyLinearStateSchema.javaClass, version = 1, mappedTypes = listOf(PersistentDummyLinearState::class.java)) { object DummyLinearStateSchemaV1 : MappedSchema(schemaFamily = DummyLinearStateSchema.javaClass, version = 1, mappedTypes = listOf(PersistentDummyLinearState::class.java)) {
override val migrationResource = "dummy-linear-v1.changelog-init"
@Entity @Entity
@Table(name = "dummy_linear_states", @Table(name = "dummy_linear_states",
indexes = arrayOf(Index(name = "external_id_idx", columnList = "external_id"), indexes = arrayOf(Index(name = "external_id_idx", columnList = "external_id"),
@ -27,6 +31,9 @@ object DummyLinearStateSchemaV1 : MappedSchema(schemaFamily = DummyLinearStateSc
/** X500Name of participant parties **/ /** X500Name of participant parties **/
@ElementCollection @ElementCollection
@CollectionTable(name="state_participants",joinColumns = arrayOf(
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
var participants: MutableSet<AbstractParty>, var participants: MutableSet<AbstractParty>,
/** /**
@ -36,6 +43,7 @@ object DummyLinearStateSchemaV1 : MappedSchema(schemaFamily = DummyLinearStateSc
var externalId: String?, var externalId: String?,
@Column(name = "uuid", nullable = false) @Column(name = "uuid", nullable = false)
@Type(type = "uuid-char")
var uuid: UUID, var uuid: UUID,
/** /**

View File

@ -14,6 +14,9 @@ import javax.persistence.Table
*/ */
object DummyLinearStateSchemaV2 : MappedSchema(schemaFamily = DummyLinearStateSchema.javaClass, version = 2, object DummyLinearStateSchemaV2 : MappedSchema(schemaFamily = DummyLinearStateSchema.javaClass, version = 2,
mappedTypes = listOf(PersistentDummyLinearState::class.java)) { mappedTypes = listOf(PersistentDummyLinearState::class.java)) {
override val migrationResource = "dummy-linear-v2.changelog-init"
@Entity @Entity
@Table(name = "dummy_linear_states_v2") @Table(name = "dummy_linear_states_v2")
class PersistentDummyLinearState( class PersistentDummyLinearState(

View File

@ -30,12 +30,7 @@ DROP TABLE IF EXISTS ${schema}.children;
DROP TABLE IF EXISTS ${schema}.parents; DROP TABLE IF EXISTS ${schema}.parents;
DROP TABLE IF EXISTS ${schema}.contract_cash_states; DROP TABLE IF EXISTS ${schema}.contract_cash_states;
DROP TABLE IF EXISTS ${schema}.messages; DROP TABLE IF EXISTS ${schema}.messages;
DROP TABLE IF EXISTS ${schema}.DummyDealStateSchemaV1$PersistentDummyDealState_participants; DROP TABLE IF EXISTS ${schema}.state_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV1$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV2$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV2$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV3$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCommercialPaperSchemaV2$PersistentCommercialPaperState_participants;
DROP TABLE IF EXISTS ${schema}.cash_states_v2; DROP TABLE IF EXISTS ${schema}.cash_states_v2;
DROP TABLE IF EXISTS ${schema}.cash_states_v3; DROP TABLE IF EXISTS ${schema}.cash_states_v3;
DROP TABLE IF EXISTS ${schema}.cp_states_v2; DROP TABLE IF EXISTS ${schema}.cp_states_v2;
@ -43,6 +38,8 @@ DROP TABLE IF EXISTS ${schema}.dummy_deal_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states; DROP TABLE IF EXISTS ${schema}.dummy_linear_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP USER IF EXISTS ${schema}; DROP USER IF EXISTS ${schema};
DROP SCHEMA IF EXISTS ${schema}; DROP SCHEMA IF EXISTS ${schema};

View File

@ -30,12 +30,7 @@ DROP TABLE IF EXISTS ${schema}.children;
DROP TABLE IF EXISTS ${schema}.parents; DROP TABLE IF EXISTS ${schema}.parents;
DROP TABLE IF EXISTS ${schema}.contract_cash_states; DROP TABLE IF EXISTS ${schema}.contract_cash_states;
DROP TABLE IF EXISTS ${schema}.messages; DROP TABLE IF EXISTS ${schema}.messages;
DROP TABLE IF EXISTS ${schema}.DummyDealStateSchemaV1$PersistentDummyDealState_participants; DROP TABLE IF EXISTS ${schema}.state_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV1$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV2$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV2$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV3$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCommercialPaperSchemaV2$PersistentCommercialPaperState_participants;
DROP TABLE IF EXISTS ${schema}.cash_states_v2; DROP TABLE IF EXISTS ${schema}.cash_states_v2;
DROP TABLE IF EXISTS ${schema}.cash_states_v3; DROP TABLE IF EXISTS ${schema}.cash_states_v3;
DROP TABLE IF EXISTS ${schema}.cp_states_v2; DROP TABLE IF EXISTS ${schema}.cp_states_v2;
@ -43,4 +38,6 @@ DROP TABLE IF EXISTS ${schema}.dummy_deal_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states; DROP TABLE IF EXISTS ${schema}.dummy_linear_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;

View File

@ -30,12 +30,7 @@ DROP TABLE IF EXISTS ${schema}.children;
DROP TABLE IF EXISTS ${schema}.parents; DROP TABLE IF EXISTS ${schema}.parents;
DROP TABLE IF EXISTS ${schema}.contract_cash_states; DROP TABLE IF EXISTS ${schema}.contract_cash_states;
DROP TABLE IF EXISTS ${schema}.messages; DROP TABLE IF EXISTS ${schema}.messages;
DROP TABLE IF EXISTS ${schema}.DummyDealStateSchemaV1$PersistentDummyDealState_participants; DROP TABLE IF EXISTS ${schema}.state_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV1$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV2$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV2$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV3$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCommercialPaperSchemaV2$PersistentCommercialPaperState_participants;
DROP TABLE IF EXISTS ${schema}.cash_states_v2; DROP TABLE IF EXISTS ${schema}.cash_states_v2;
DROP TABLE IF EXISTS ${schema}.cash_states_v3; DROP TABLE IF EXISTS ${schema}.cash_states_v3;
DROP TABLE IF EXISTS ${schema}.cp_states_v2; DROP TABLE IF EXISTS ${schema}.cp_states_v2;
@ -44,6 +39,8 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP USER IF EXISTS ${schema}; DROP USER IF EXISTS ${schema};
DROP LOGIN ${schema}; DROP LOGIN ${schema};
DROP SCHEMA IF EXISTS ${schema}; DROP SCHEMA IF EXISTS ${schema};

View File

@ -30,12 +30,7 @@ DROP TABLE IF EXISTS ${schema}.children;
DROP TABLE IF EXISTS ${schema}.parents; DROP TABLE IF EXISTS ${schema}.parents;
DROP TABLE IF EXISTS ${schema}.contract_cash_states; DROP TABLE IF EXISTS ${schema}.contract_cash_states;
DROP TABLE IF EXISTS ${schema}.messages; DROP TABLE IF EXISTS ${schema}.messages;
DROP TABLE IF EXISTS ${schema}.DummyDealStateSchemaV1$PersistentDummyDealState_participants; DROP TABLE IF EXISTS ${schema}.state_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV1$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV2$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV2$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV3$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCommercialPaperSchemaV2$PersistentCommercialPaperState_participants;
DROP TABLE IF EXISTS ${schema}.cash_states_v2; DROP TABLE IF EXISTS ${schema}.cash_states_v2;
DROP TABLE IF EXISTS ${schema}.cash_states_v3; DROP TABLE IF EXISTS ${schema}.cash_states_v3;
DROP TABLE IF EXISTS ${schema}.cp_states_v2; DROP TABLE IF EXISTS ${schema}.cp_states_v2;
@ -44,6 +39,8 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP USER IF EXISTS ${schema}; DROP USER IF EXISTS ${schema};
DROP LOGIN ${schema}; DROP LOGIN ${schema};
DROP SCHEMA IF EXISTS ${schema}; DROP SCHEMA IF EXISTS ${schema};

View File

@ -30,12 +30,7 @@ DROP TABLE IF EXISTS ${schema}.children;
DROP TABLE IF EXISTS ${schema}.parents; DROP TABLE IF EXISTS ${schema}.parents;
DROP TABLE IF EXISTS ${schema}.contract_cash_states; DROP TABLE IF EXISTS ${schema}.contract_cash_states;
DROP TABLE IF EXISTS ${schema}.messages; DROP TABLE IF EXISTS ${schema}.messages;
DROP TABLE IF EXISTS ${schema}.DummyDealStateSchemaV1$PersistentDummyDealState_participants; DROP TABLE IF EXISTS ${schema}.state_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV1$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV2$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV2$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV3$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCommercialPaperSchemaV2$PersistentCommercialPaperState_participants;
DROP TABLE IF EXISTS ${schema}.cash_states_v2; DROP TABLE IF EXISTS ${schema}.cash_states_v2;
DROP TABLE IF EXISTS ${schema}.cash_states_v3; DROP TABLE IF EXISTS ${schema}.cash_states_v3;
DROP TABLE IF EXISTS ${schema}.cp_states_v2; DROP TABLE IF EXISTS ${schema}.cp_states_v2;
@ -44,6 +39,8 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2; DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion; DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence; DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
IF NOT EXISTS (SELECT schema_name FROM information_schema.schemata WHERE schema_name = '${schema}') EXEC('CREATE SCHEMA ${schema}'); IF NOT EXISTS (SELECT schema_name FROM information_schema.schemata WHERE schema_name = '${schema}') EXEC('CREATE SCHEMA ${schema}');
IF NOT EXISTS (SELECT * FROM sys.sysusers WHERE name='${schema}') CREATE USER ${schema} FOR LOGIN ${schema} WITH DEFAULT_SCHEMA = ${schema}; IF NOT EXISTS (SELECT * FROM sys.sysusers WHERE name='${schema}') CREATE USER ${schema} FOR LOGIN ${schema} WITH DEFAULT_SCHEMA = ${schema};
GRANT ALTER, DELETE, EXECUTE, INSERT, REFERENCES, SELECT, UPDATE, VIEW DEFINITION ON SCHEMA::${schema} TO ${schema}; GRANT ALTER, DELETE, EXECUTE, INSERT, REFERENCES, SELECT, UPDATE, VIEW DEFINITION ON SCHEMA::${schema} TO ${schema};

View File

@ -0,0 +1,24 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<changeSet author="tudormalene (generated)" id="1512743551377-8">
<createTable tableName="dummy_deal_states">
<column name="output_index" type="INT(10)">
<constraints nullable="false"/>
</column>
<column name="transaction_id" type="VARCHAR(64)">
<constraints nullable="false"/>
</column>
<column name="external_id" type="VARCHAR(255)"/>
<column name="uuid" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>

Some files were not shown because too many files have changed in this diff Show More