diff --git a/.ci/api-current.txt b/.ci/api-current.txt index 7225772d13..87874e2381 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -4339,21 +4339,19 @@ public class net.corda.core.schemas.PersistentState extends java.lang.Object imp @Embeddable public class net.corda.core.schemas.PersistentStateRef extends java.lang.Object implements java.io.Serializable public () - public (String, Integer) + public (String, int) public (net.corda.core.contracts.StateRef) - @Nullable - public final String component1() - @Nullable - public final Integer component2() @NotNull - public final net.corda.core.schemas.PersistentStateRef copy(String, Integer) + public final String component1() + public final int component2() + @NotNull + public final net.corda.core.schemas.PersistentStateRef copy(String, int) public boolean equals(Object) - @Nullable - public Integer getIndex() - @Nullable + public int getIndex() + @NotNull public String getTxId() public int hashCode() - public void setIndex(Integer) + public void setIndex(int) public void setTxId(String) public String toString() ## diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5cdaa2e867..9722f81219 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -76,7 +76,7 @@ see changes to this list. * George Smetana (Bradesco) * Giulio Katis (Westpac) * Giuseppe Cardone (Intesa Sanpaolo) -* Guy Hochstetler (IBM) +* Guy Hochstetler (R3) * Ian Cusden (UBS) * Ian Grigg (R3) * Igor Nitto (R3) diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt index f93b850392..c8b5f09ac0 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt @@ -49,6 +49,7 @@ import net.corda.core.utilities.toBase58String import org.bouncycastle.asn1.x509.KeyPurposeId import java.lang.reflect.Modifier import java.math.BigDecimal +import java.nio.charset.StandardCharsets.UTF_8 import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.CertificateFactory @@ -426,7 +427,7 @@ object JacksonSupport { @Deprecated("This is an internal class, do not use") object OpaqueBytesDeserializer : JsonDeserializer() { override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): OpaqueBytes { - return OpaqueBytes(parser.binaryValue) + return OpaqueBytes(parser.text?.toByteArray(UTF_8) ?: parser.binaryValue) } } diff --git a/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt b/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt index b13d576e30..19ecbb1805 100644 --- a/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt +++ b/client/jackson/src/test/kotlin/net/corda/client/jackson/JacksonSupportTest.kt @@ -49,6 +49,7 @@ import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters import java.math.BigInteger +import java.nio.charset.StandardCharsets.* import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.X509Certificate @@ -113,12 +114,17 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory: } @Test - fun OpaqueBytes() { + fun `OpaqueBytes serialization`() { val opaqueBytes = OpaqueBytes(secureRandomBytes(128)) val json = mapper.valueToTree(opaqueBytes) assertThat(json.binaryValue()).isEqualTo(opaqueBytes.bytes) assertThat(json.asText()).isEqualTo(opaqueBytes.bytes.toBase64()) - assertThat(mapper.convertValue(json)).isEqualTo(opaqueBytes) + } + + @Test + fun `OpaqueBytes deserialization`() { + assertThat(mapper.convertValue(TextNode("1234"))).isEqualTo(OpaqueBytes("1234".toByteArray(UTF_8))) + assertThat(mapper.convertValue(BinaryNode(byteArrayOf(1, 2, 3, 4)))).isEqualTo(OpaqueBytes.of(1, 2, 3, 4)) } @Test diff --git a/core/src/main/kotlin/net/corda/core/node/NetworkParameters.kt b/core/src/main/kotlin/net/corda/core/node/NetworkParameters.kt index 935aae08a6..b4dc80188e 100644 --- a/core/src/main/kotlin/net/corda/core/node/NetworkParameters.kt +++ b/core/src/main/kotlin/net/corda/core/node/NetworkParameters.kt @@ -13,6 +13,7 @@ package net.corda.core.node import net.corda.core.identity.Party import net.corda.core.node.services.AttachmentId import net.corda.core.serialization.CordaSerializable +import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.utilities.days import java.time.Duration import java.time.Instant @@ -33,7 +34,7 @@ import java.time.Instant * during this period */ @CordaSerializable -data class NetworkParameters @JvmOverloads constructor( +data class NetworkParameters( val minimumPlatformVersion: Int, val notaries: List, val maxMessageSize: Int, @@ -41,8 +42,26 @@ data class NetworkParameters @JvmOverloads constructor( val modifiedTime: Instant, val epoch: Int, val whitelistedContractImplementations: Map>, - val eventHorizon: Duration = Int.MAX_VALUE.days + val eventHorizon: Duration ) { + @DeprecatedConstructorForDeserialization(1) + constructor (minimumPlatformVersion: Int, + notaries: List, + maxMessageSize: Int, + maxTransactionSize: Int, + modifiedTime: Instant, + epoch: Int, + whitelistedContractImplementations: Map> + ) : this(minimumPlatformVersion, + notaries, + maxMessageSize, + maxTransactionSize, + modifiedTime, + epoch, + whitelistedContractImplementations, + Int.MAX_VALUE.days + ) + init { require(minimumPlatformVersion > 0) { "minimumPlatformVersion must be at least 1" } require(notaries.distinctBy { it.identity } == notaries) { "Duplicate notary identities" } diff --git a/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt b/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt index e16a7b8d42..2ee20228c7 100644 --- a/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt +++ b/core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt @@ -66,7 +66,7 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers /** [OwnableState] attributes */ /** X500Name of owner party **/ - @Column(name = "owner_name") + @Column(name = "owner_name", nullable = true) var owner: AbstractParty, /** [FungibleAsset] attributes @@ -76,16 +76,16 @@ object CommonSchemaV1 : MappedSchema(schemaFamily = CommonSchema.javaClass, vers */ /** Amount attributes */ - @Column(name = "quantity") + @Column(name = "quantity", nullable = false) var quantity: Long, /** Issuer attributes */ /** X500Name of issuer party **/ - @Column(name = "issuer_name") + @Column(name = "issuer_name", nullable = true) var issuer: AbstractParty, - @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var issuerRef: ByteArray ) : PersistentState() diff --git a/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt b/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt index 84fa3f6d7f..0e1ea95210 100644 --- a/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt +++ b/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt @@ -97,11 +97,11 @@ class PersistentState(@EmbeddedId var stateRef: PersistentStateRef? = null) : St */ @Embeddable data class PersistentStateRef( - @Column(name = "transaction_id", length = 64) - var txId: String? = null, + @Column(name = "transaction_id", length = 64, nullable = false) + var txId: String, - @Column(name = "output_index") - var index: Int? = null + @Column(name = "output_index", nullable = false) + var index: Int ) : Serializable { constructor(stateRef: StateRef) : this(stateRef.txhash.bytes.toHexString(), stateRef.index) } diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index f4cddf75ba..9bef076789 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -97,6 +97,12 @@ Unreleased reference to the outer class) as per the Java documentation `here `_ we are disallowing this as the paradigm in general makes little sense for contract states. +* API change: ``net.corda.core.schemas.PersistentStateRef`` fields (index and txId) are now non-nullable. + The fields were always effectively non-nullable - values were set from non-nullable fields of other objects. + The class is used as database Primary Key columns of other entities and databases already impose those columns as non-nullable + (even if JPA annotation nullable=false was absent). + In case your Cordapps use this entity class to persist data in own custom tables as non Primary Key columns refer to :doc:`upgrade-notes` for upgrade instructions. + * Update the fast-classpath-scanner dependent library version from 2.0.21 to 2.12.3 * Added `database.hibernateDialect` node configuration option diff --git a/docs/source/corda-configuration-file.rst b/docs/source/corda-configuration-file.rst index d79fa784cc..379f4810af 100644 --- a/docs/source/corda-configuration-file.rst +++ b/docs/source/corda-configuration-file.rst @@ -208,7 +208,7 @@ absolute path to the node's base directory. :sshd: If provided, node will start internal SSH server which will provide a management shell. It uses the same credentials and permissions as RPC subsystem. It has one required parameter. - :port: The port to start SSH server on + :port: The port to start SSH server on e.g. ``sshd { port = 2222 }``. :relay: If provided, the node will attempt to tunnel inbound connections via an external relay. The relay's address will be advertised to the network map service instead of the provided ``p2pAddress``. diff --git a/docs/source/serialization-default-evolution.rst b/docs/source/serialization-default-evolution.rst index 282ca452b8..1f4923a357 100644 --- a/docs/source/serialization-default-evolution.rst +++ b/docs/source/serialization-default-evolution.rst @@ -64,7 +64,7 @@ above. A sensible default for the missing value is provided for instantiation of order, see the discussion below. As before, instances of the class at version A will be able to deserialize serialized forms of example B as it -will simply treat them as if the property has been removed (as from its perspective, they will have been.) +will simply treat them as if the property has been removed (as from its perspective, they will have been). Constructor Versioning @@ -144,7 +144,6 @@ be: // The third alteration, and how it currently exists, property e added data class Example3 (val a: Int, val b: Int, val c: Int, val d: Int, val: Int e) { - // NOTE: version number purposefully omitted from annotation for demonstration purposes @DeprecatedConstructorForDeserialization(1) constructor (a: Int, b: Int) : this(a, b, -1, -1, -1) // alt constructor 1 @DeprecatedConstructorForDeserialization(2) diff --git a/docs/source/shell.rst b/docs/source/shell.rst index 8e649fc5b0..bbd76cdf0b 100644 --- a/docs/source/shell.rst +++ b/docs/source/shell.rst @@ -269,9 +269,9 @@ SecureHash ~~~~~~~~~~ A parameter of type ``SecureHash`` can be written as a hexadecimal string: ``F69A7626ACC27042FEEAE187E6BFF4CE666E6F318DC2B32BE9FAF87DF687930C`` -OpaqueBytes and SerializedBytes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A parameter of type ``OpaqueBytes`` can be provided as a string in Base64. +OpaqueBytes +~~~~~~~~~~~ +A parameter of type ``OpaqueBytes`` can be provided as a UTF-8 string. PublicKey and CompositeKey ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/upgrade-notes.rst b/docs/source/upgrade-notes.rst index a188e94b2b..29be5e1fca 100644 --- a/docs/source/upgrade-notes.rst +++ b/docs/source/upgrade-notes.rst @@ -29,6 +29,44 @@ versions you are currently using are still in force. We also strongly recommend cross referencing with the :doc:`changelog` to confirm changes. +UNRELEASED +---------- + +<<< Fill this in >>> + +* API change: ``net.corda.core.schemas.PersistentStateRef`` fields (``index`` and ``txId``) incorrectly marked as nullable are now non-nullable, + :doc:`changelog` contains the explanation. + + H2 database upgrade action: + + For Cordapps persisting custom entities with ``PersistentStateRef`` used as non Primary Key column, the backing table needs to be updated, + In SQL replace ``your_transaction_id``/``your_output_index`` column names with your custom names, if entity didn't used JPA ``@AttributeOverrides`` + then default names are ``transaction_id`` and ``output_index``. + + .. sourcecode:: sql + + SELECT count(*) FROM [YOUR_PersistentState_TABLE_NAME] WHERE your_transaction_id IS NULL OR your_output_index IS NULL; + + In case your table already contains rows with NULL columns, and the logic doesn't distinguish between NULL and an empty string, + all NULL column occurrences can be changed to an empty string: + + .. sourcecode:: sql + + UPDATE [YOUR_PersistentState_TABLE_NAME] SET your_transaction_id="" WHERE your_transaction_id IS NULL; + UPDATE [YOUR_PersistentState_TABLE_NAME] SET your_output_index="" WHERE your_output_index IS NULL; + + If all rows have NON NULL ``transaction_ids`` and ``output_idx`` or you have assigned empty string values, then it's safe to update the table: + + .. sourcecode:: sql + + ALTER TABLE [YOUR_PersistentState_TABLE_NAME] ALTER COLUMN your_transaction_id SET NOT NULL; + ALTER TABLE [YOUR_PersistentState_TABLE_NAME] ALTER COLUMN your_output_index SET NOT NULL; + + If the table already contains rows with NULL values, and the logic caters differently between NULL and an empty string, + and the logic has to be preserved you would need to create copy of ``PersistentStateRef`` class with different name and use the new class in your entity. + + No action is needed for default node tables as ``PersistentStateRef`` is used as Primary Key only and the backing columns are automatically not nullable + or custom Cordapp entities using ``PersistentStateRef`` as Primary Key. Upgrading to R3 Corda V3.0 Developer Preview -------------------------------------------- diff --git a/finance/src/main/kotlin/net/corda/finance/flows/CashExitFlow.kt b/finance/src/main/kotlin/net/corda/finance/flows/CashExitFlow.kt index dfa3e6788e..4e1e66857a 100644 --- a/finance/src/main/kotlin/net/corda/finance/flows/CashExitFlow.kt +++ b/finance/src/main/kotlin/net/corda/finance/flows/CashExitFlow.kt @@ -25,6 +25,9 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.ProgressTracker import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.cash.selection.AbstractCashSelection +import net.corda.finance.flows.AbstractCashFlow.Companion.FINALISING_TX +import net.corda.finance.flows.AbstractCashFlow.Companion.GENERATING_TX +import net.corda.finance.flows.AbstractCashFlow.Companion.SIGNING_TX import net.corda.finance.issuedBy import java.util.* diff --git a/finance/src/main/kotlin/net/corda/finance/flows/CashIssueFlow.kt b/finance/src/main/kotlin/net/corda/finance/flows/CashIssueFlow.kt index 13018f69d0..8614ca1318 100644 --- a/finance/src/main/kotlin/net/corda/finance/flows/CashIssueFlow.kt +++ b/finance/src/main/kotlin/net/corda/finance/flows/CashIssueFlow.kt @@ -19,6 +19,9 @@ import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.ProgressTracker import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.AbstractCashFlow.Companion.FINALISING_TX +import net.corda.finance.flows.AbstractCashFlow.Companion.GENERATING_TX +import net.corda.finance.flows.AbstractCashFlow.Companion.SIGNING_TX import net.corda.finance.issuedBy import java.util.* diff --git a/finance/src/main/kotlin/net/corda/finance/flows/CashPaymentFlow.kt b/finance/src/main/kotlin/net/corda/finance/flows/CashPaymentFlow.kt index 7c809bcc65..4f5b785e9a 100644 --- a/finance/src/main/kotlin/net/corda/finance/flows/CashPaymentFlow.kt +++ b/finance/src/main/kotlin/net/corda/finance/flows/CashPaymentFlow.kt @@ -21,6 +21,10 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.ProgressTracker import net.corda.finance.contracts.asset.Cash +import net.corda.finance.flows.AbstractCashFlow.Companion.FINALISING_TX +import net.corda.finance.flows.AbstractCashFlow.Companion.GENERATING_ID +import net.corda.finance.flows.AbstractCashFlow.Companion.GENERATING_TX +import net.corda.finance.flows.AbstractCashFlow.Companion.SIGNING_TX import java.util.* /** diff --git a/finance/src/main/kotlin/net/corda/finance/schemas/CashSchemaV1.kt b/finance/src/main/kotlin/net/corda/finance/schemas/CashSchemaV1.kt index 91178ca5f3..957b388cd0 100644 --- a/finance/src/main/kotlin/net/corda/finance/schemas/CashSchemaV1.kt +++ b/finance/src/main/kotlin/net/corda/finance/schemas/CashSchemaV1.kt @@ -38,19 +38,19 @@ object CashSchemaV1 : MappedSchema( @Table(name = "contract_cash_states", indexes = [Index(name = "ccy_code_idx", columnList = "ccy_code"), Index(name = "pennies_idx", columnList = "pennies")]) class PersistentCashState( /** X500Name of owner party **/ - @Column(name = "owner_name") + @Column(name = "owner_name", nullable = true) var owner: AbstractParty, - @Column(name = "pennies") + @Column(name = "pennies", nullable = false) var pennies: Long, - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, - @Column(name = "issuer_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "issuer_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var issuerPartyHash: String, - @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var issuerRef: ByteArray ) : PersistentState() diff --git a/finance/src/main/kotlin/net/corda/finance/schemas/CommercialPaperSchemaV1.kt b/finance/src/main/kotlin/net/corda/finance/schemas/CommercialPaperSchemaV1.kt index 84a23a1e3b..8d1e213ea4 100644 --- a/finance/src/main/kotlin/net/corda/finance/schemas/CommercialPaperSchemaV1.kt +++ b/finance/src/main/kotlin/net/corda/finance/schemas/CommercialPaperSchemaV1.kt @@ -40,29 +40,29 @@ object CommercialPaperSchemaV1 : MappedSchema( @Entity @Table(name = "cp_states", indexes = [Index(name = "ccy_code_index", columnList = "ccy_code"), Index(name = "maturity_index", columnList = "maturity_instant"), Index(name = "face_value_index", columnList = "face_value")]) class PersistentCommercialPaperState( - @Column(name = "issuance_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "issuance_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var issuancePartyHash: String, - @Column(name = "issuance_ref") + @Column(name = "issuance_ref", nullable = false) @Type(type = "corda-wrapper-binary") var issuanceRef: ByteArray, - @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var ownerHash: String, - @Column(name = "maturity_instant") + @Column(name = "maturity_instant", nullable = false) var maturity: Instant, - @Column(name = "face_value") + @Column(name = "face_value", nullable = false) var faceValue: Long, - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, - @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var faceValueIssuerPartyHash: String, - @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var faceValueIssuerRef: ByteArray ) : PersistentState() diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt index 190883038a..c5aadb2c37 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt @@ -254,7 +254,7 @@ class CommercialPaperTestsGeneric { // MegaCorp will issue some commercial paper and Alice will buy it, using cash issued to her in the name // of the dummy cash issuer. - val allIdentities = arrayOf(megaCorp.identity, miniCorp.identity, dummyCashIssuer.identity, dummyNotary.identity) + val allIdentities = arrayOf(megaCorp.identity, alice.identity, dummyCashIssuer.identity, dummyNotary.identity) val notaryServices = MockServices(dummyNotary) val issuerServices = MockServices(dummyCashIssuer, dummyNotary) val (aliceDatabase, aliceServices) = makeTestDatabaseAndMockServices( diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt index 1c2d732e78..14019d271d 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt @@ -92,10 +92,11 @@ class CashTests { LogHelper.setLevel(NodeVaultService::class) megaCorpServices = MockServices(megaCorp) miniCorpServices = MockServices(miniCorp) + val myself = TestIdentity(CordaX500Name("Me", "London", "GB")) val databaseAndServices = makeTestDatabaseAndMockServices( listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"), - makeTestIdentityService(megaCorp.identity, miniCorp.identity, dummyCashIssuer.identity, dummyNotary.identity), - TestIdentity(CordaX500Name("Me", "London", "GB")) + makeTestIdentityService(megaCorp.identity, miniCorp.identity, dummyCashIssuer.identity, dummyNotary.identity, myself.identity), + myself ) database = databaseAndServices.first ourServices = databaseAndServices.second diff --git a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV1.kt b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV1.kt index eeb398bc2d..e1c61219b5 100644 --- a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV1.kt +++ b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV1.kt @@ -36,19 +36,19 @@ object SampleCashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, ve @Entity @Table(name = "contract_cash_states_v1", indexes = [Index(name = "ccy_code_idx", columnList = "ccy_code"), Index(name = "pennies_idx", columnList = "pennies")]) class PersistentCashState( - @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var ownerHash: String, - @Column(name = "pennies") + @Column(name = "pennies", nullable = false) var pennies: Long, - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, - @Column(name = "issuer_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "issuer_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var issuerPartyHash: String, - @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var issuerRef: ByteArray ) : PersistentState() diff --git a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV2.kt b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV2.kt index 0ec686e5dd..681713f7bc 100644 --- a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV2.kt +++ b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV2.kt @@ -28,7 +28,7 @@ object SampleCashSchemaV2 : MappedSchema(schemaFamily = CashSchema.javaClass, ve @Table(name = "cash_states_v2", indexes = [Index(name = "ccy_code_idx2", columnList = "ccy_code")]) class PersistentCashState( /** product type */ - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, participants: Set, owner: AbstractParty, @@ -38,7 +38,7 @@ object SampleCashSchemaV2 : MappedSchema(schemaFamily = CashSchema.javaClass, ve ) : CommonSchemaV1.FungibleState(participants.toMutableSet(), owner, quantity, issuerParty, issuerRef.bytes) { @ElementCollection - @Column(name = "participants") + @Column(name = "participants", nullable = true) @CollectionTable(name = "cash_states_v2_participants", joinColumns = [JoinColumn(name = "output_index", referencedColumnName = "output_index"), JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")]) override var participants: MutableSet? = null } diff --git a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV3.kt b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV3.kt index d21ff2d6f0..b484cb1089 100644 --- a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV3.kt +++ b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV3.kt @@ -39,20 +39,20 @@ object SampleCashSchemaV3 : MappedSchema(schemaFamily = CashSchema.javaClass, ve var participants: MutableSet? = null, /** X500Name of owner party **/ - @Column(name = "owner_name") + @Column(name = "owner_name", nullable = true) var owner: AbstractParty, - @Column(name = "pennies") + @Column(name = "pennies", nullable = false) var pennies: Long, - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, /** X500Name of issuer party **/ - @Column(name = "issuer_name") + @Column(name = "issuer_name", nullable = true) var issuer: AbstractParty, - @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var issuerRef: ByteArray ) : PersistentState() diff --git a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV1.kt b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV1.kt index 2e8a098a51..8bd67c950a 100644 --- a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV1.kt +++ b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV1.kt @@ -37,29 +37,29 @@ object SampleCommercialPaperSchemaV1 : MappedSchema(schemaFamily = CommercialPap @Entity @Table(name = "cp_states_v1", indexes = [Index(name = "ccy_code_index", columnList = "ccy_code"), Index(name = "maturity_index", columnList = "maturity_instant"), Index(name = "face_value_index", columnList = "face_value")]) class PersistentCommercialPaperState( - @Column(name = "issuance_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "issuance_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var issuancePartyHash: String, - @Column(name = "issuance_ref") + @Column(name = "issuance_ref", nullable = false) @Type(type = "corda-wrapper-binary") var issuanceRef: ByteArray, - @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "owner_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var ownerHash: String, - @Column(name = "maturity_instant") + @Column(name = "maturity_instant", nullable = false) var maturity: Instant, - @Column(name = "face_value") + @Column(name = "face_value", nullable = false) var faceValue: Long, - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, - @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var faceValueIssuerPartyHash: String, - @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var faceValueIssuerRef: ByteArray ) : PersistentState() diff --git a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV2.kt b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV2.kt index aa5d88d329..323a743843 100644 --- a/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV2.kt +++ b/finance/src/test/kotlin/net/corda/finance/schemas/SampleCommercialPaperSchemaV2.kt @@ -32,16 +32,16 @@ object SampleCommercialPaperSchemaV2 : MappedSchema(schemaFamily = CommercialPap @Entity @Table(name = "cp_states_v2", indexes = [Index(name = "ccy_code_index2", columnList = "ccy_code"), Index(name = "maturity_index2", columnList = "maturity_instant")]) class PersistentCommercialPaperState( - @Column(name = "maturity_instant") + @Column(name = "maturity_instant", nullable = false) var maturity: Instant, - @Column(name = "ccy_code", length = 3) + @Column(name = "ccy_code", length = 3, nullable = false) var currency: String, - @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "face_value_issuer_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var faceValueIssuerPartyHash: String, - @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "face_value_issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var faceValueIssuerRef: ByteArray, diff --git a/node/src/integration-test/kotlin/net/corda/testMessage/MessageState.kt b/node/src/integration-test/kotlin/net/corda/testMessage/MessageState.kt index 335a507d96..9a35a92cce 100644 --- a/node/src/integration-test/kotlin/net/corda/testMessage/MessageState.kt +++ b/node/src/integration-test/kotlin/net/corda/testMessage/MessageState.kt @@ -42,10 +42,10 @@ object MessageSchemaV1 : MappedSchema( @Entity @Table(name = "messages") class PersistentMessage( - @Column(name = "message_by") + @Column(name = "message_by", nullable = false) var by: String, - @Column(name = "message_value") + @Column(name = "message_value", nullable = false) var value: String ) : PersistentState() } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index eda6960efa..7ae01af130 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -305,8 +305,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val identityService = makeIdentityService(identity.certificate) networkMapClient = configuration.networkServices?.let { NetworkMapClient(it.networkMapURL, identityService.trustRoot) } - - val networkParameters = NetworkParametersReader(identityService.trustRoot, networkMapClient, configuration.baseDirectory).networkParameters + val networkParameteresReader = NetworkParametersReader(identityService.trustRoot, networkMapClient, configuration.baseDirectory) + val networkParameters = networkParameteresReader.networkParameters check(networkParameters.minimumPlatformVersion <= versionInfo.platformVersion) { "Node's platform version is lower than network's required minimumPlatformVersion" } @@ -384,7 +384,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, networkMapUpdater = NetworkMapUpdater(services.networkMapCache, NodeInfoWatcher(configuration.baseDirectory, getRxIoScheduler(), Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec)), networkMapClient, - networkParameters.serialize().hash, + networkParameteresReader.hash, services.myInfo.serialize().hash, configuration.baseDirectory, configuration.extraNetworkMapKeys) diff --git a/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt b/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt index bc95b912bf..debe5ed3b5 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NetworkParametersReader.kt @@ -31,11 +31,14 @@ class NetworkParametersReader(private val trustRoot: X509Certificate, private val logger = contextLogger() } + private data class NetworkParamsAndHash(val networkParameters: NetworkParameters, val hash: SecureHash) private val networkParamsFile = baseDirectory / NETWORK_PARAMS_FILE_NAME private val parametersUpdateFile = baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME - val networkParameters by lazy { retrieveNetworkParameters() } + private val netParamsAndHash by lazy { retrieveNetworkParameters() } + val networkParameters get() = netParamsAndHash.networkParameters + val hash get() = netParamsAndHash.hash - private fun retrieveNetworkParameters(): NetworkParameters { + private fun retrieveNetworkParameters(): NetworkParamsAndHash { val advertisedParametersHash = try { networkMapClient?.getNetworkMap()?.payload?.networkParameterHash } catch (e: Exception) { @@ -53,17 +56,17 @@ class NetworkParametersReader(private val trustRoot: X509Certificate, // on the other we have parameters update process - it needs to be unified. Say you start the node, you don't have matching parameters, // you get them from network map, but you have to run the approval step. if (signedParametersFromFile == null) { // Node joins for the first time. - downloadParameters(trustRoot, advertisedParametersHash) + downloadParameters(advertisedParametersHash) } else if (signedParametersFromFile.raw.hash == advertisedParametersHash) { // Restarted with the same parameters. - signedParametersFromFile.verifiedNetworkMapCert(trustRoot) + signedParametersFromFile } else { // Update case. - readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash).verifiedNetworkMapCert(trustRoot) + readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash) } } else { // No compatibility zone configured. Node should proceed with parameters from file. - signedParametersFromFile?.verifiedNetworkMapCert(trustRoot) ?: throw IllegalArgumentException("Couldn't find network parameters file and compatibility zone wasn't configured/isn't reachable") + signedParametersFromFile ?: throw IllegalArgumentException("Couldn't find network parameters file and compatibility zone wasn't configured/isn't reachable") } logger.info("Loaded network parameters: $parameters") - return parameters + return NetworkParamsAndHash(parameters.verifiedNetworkMapCert(trustRoot), parameters.raw.hash) } private fun readParametersUpdate(advertisedParametersHash: SecureHash, previousParametersHash: SecureHash): SignedNetworkParameters { @@ -84,14 +87,13 @@ class NetworkParametersReader(private val trustRoot: X509Certificate, } // Used only when node joins for the first time. - private fun downloadParameters(trustRoot: X509Certificate, parametersHash: SecureHash): NetworkParameters { + private fun downloadParameters(parametersHash: SecureHash): SignedNetworkParameters { logger.info("No network-parameters file found. Expecting network parameters to be available from the network map.") val networkMapClient = checkNotNull(networkMapClient) { "Node hasn't been configured to connect to a network map from which to get the network parameters" } val signedParams = networkMapClient.getNetworkParameters(parametersHash) - val verifiedParams = signedParams.verifiedNetworkMapCert(trustRoot) signedParams.serialize().open().copyTo(baseDirectory / NETWORK_PARAMS_FILE_NAME) - return verifiedParams + return signedParams } } diff --git a/node/src/main/kotlin/net/corda/node/internal/schemas/NodeInfoSchema.kt b/node/src/main/kotlin/net/corda/node/internal/schemas/NodeInfoSchema.kt index 53af2f635a..e27661cc51 100644 --- a/node/src/main/kotlin/net/corda/node/internal/schemas/NodeInfoSchema.kt +++ b/node/src/main/kotlin/net/corda/node/internal/schemas/NodeInfoSchema.kt @@ -38,25 +38,25 @@ object NodeInfoSchemaV1 : MappedSchema( class PersistentNodeInfo( @Id @GeneratedValue - @Column(name = "node_info_id") + @Column(name = "node_info_id", nullable = false) var id: Int, - @Column(name = "node_info_hash", length = 64) + @Column(name = "node_info_hash", length = 64, nullable = false) val hash: String, - @Column(name = "addresses") + @Column(name = "addresses", nullable = false) @OneToMany(cascade = [(CascadeType.ALL)], orphanRemoval = true) @JoinColumn(name = "node_info_id", foreignKey = ForeignKey(name = "FK__info_hosts__infos")) val addresses: List, - @Column(name = "legal_identities_certs") + @Column(name = "legal_identities_certs", nullable = false) @ManyToMany(cascade = [(CascadeType.ALL)]) @JoinTable(name = "node_link_nodeinfo_party", joinColumns = [(JoinColumn(name = "node_info_id", foreignKey = ForeignKey(name = "FK__link_nodeinfo_party__infos")))], inverseJoinColumns = [(JoinColumn(name = "party_name", foreignKey = ForeignKey(name = "FK__link_ni_p__info_p_cert")))]) val legalIdentitiesAndCerts: List, - @Column(name = "platform_version") + @Column(name = "platform_version", nullable = false) val platformVersion: Int, /** @@ -64,7 +64,7 @@ object NodeInfoSchemaV1 : MappedSchema( * Not expected to be sequential, but later versions of the registration must have higher values * Similar to the serial number on DNS records. */ - @Column(name = "serial") + @Column(name = "serial", nullable = false) val serial: Long ) : Serializable { fun toNodeInfo(): NodeInfo { @@ -82,7 +82,7 @@ object NodeInfoSchemaV1 : MappedSchema( data class DBHostAndPort( @Id @GeneratedValue - @Column(name = "hosts_id") + @Column(name = "hosts_id", nullable = false) var id: Int, val host: String? = null, val port: Int? = null @@ -108,11 +108,11 @@ object NodeInfoSchemaV1 : MappedSchema( @Column(name = "party_name", nullable = false) val name: String, - @Column(name = "owning_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "owning_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) val owningKeyHash: String, @Lob - @Column(name = "party_cert_binary") + @Column(name = "party_cert_binary", nullable = false) val partyCertBinary: ByteArray, val isMain: Boolean, diff --git a/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt b/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt index b0d5095ad4..d9440cabf8 100644 --- a/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt +++ b/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt @@ -142,7 +142,7 @@ class NodeSchedulerService(private val clock: CordaClock, @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}scheduled_states") class PersistentScheduledState( @EmbeddedId - var output: PersistentStateRef = PersistentStateRef(), + var output: PersistentStateRef, @Column(name = "scheduled_at", nullable = false) var scheduledAt: Instant = Instant.now() diff --git a/node/src/main/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepository.kt b/node/src/main/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepository.kt index d5cb3a94d8..10624f9c96 100644 --- a/node/src/main/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepository.kt +++ b/node/src/main/kotlin/net/corda/node/services/events/PersistentScheduledFlowRepository.kt @@ -18,8 +18,8 @@ class PersistentScheduledFlowRepository(val database: CordaPersistence) : Schedu } private fun toPersistentEntity(key: StateRef, value: ScheduledStateRef): NodeSchedulerService.PersistentScheduledState { - return NodeSchedulerService.PersistentScheduledState().apply { - output = PersistentStateRef(key.txhash.toString(), key.index) + val output = PersistentStateRef(key.txhash.toString(), key.index) + return NodeSchedulerService.PersistentScheduledState(output).apply { scheduledAt = value.scheduledAt } } diff --git a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt index acae901c5f..9490751842 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt @@ -88,11 +88,11 @@ class PersistentIdentityService(override val trustRoot: X509Certificate, @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}identities") class PersistentIdentity( @Id - @Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE) - var publicKeyHash: String, + @Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = false) + var publicKeyHash: String = "", @Lob - @Column(name = "identity_value") + @Column(name = "identity_value", nullable = false) var identity: ByteArray = EMPTY_BYTE_ARRAY ) : Serializable @@ -100,10 +100,10 @@ class PersistentIdentityService(override val trustRoot: X509Certificate, @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}named_identities") class PersistentIdentityNames( @Id - @Column(name = "name", length = 128) + @Column(name = "name", length = 128, nullable = false) var name: String = "", - @Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var publicKeyHash: String = "" ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt index fc7f039ce9..3d06fef7e7 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt @@ -43,14 +43,14 @@ class PersistentKeyManagementService(val identityService: IdentityService, @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}our_key_pairs") class PersistentKey( @Id - @Column(name = "public_key_hash", length = MAX_HASH_HEX_SIZE) + @Column(name = "public_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false) var publicKeyHash: String, @Lob - @Column(name = "public_key") + @Column(name = "public_key", nullable = false) var publicKey: ByteArray = EMPTY_BYTE_ARRAY, @Lob - @Column(name = "private_key") + @Column(name = "private_key", nullable = false) var privateKey: ByteArray = EMPTY_BYTE_ARRAY ) : Serializable { constructor(publicKey: PublicKey, privateKey: PrivateKey) diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt index bd71ad6167..fdeb3ffa37 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt @@ -150,16 +150,16 @@ class P2PMessageDeduplicator(private val database: CordaPersistence) { @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}message_ids") class ProcessedMessage( @Id - @Column(name = "message_id", length = 64) + @Column(name = "message_id", length = 64, nullable = false) var id: String = "", - @Column(name = "insertion_time") + @Column(name = "insertion_time", nullable = false) var insertionTime: Instant = Instant.now(), - @Column(name = "sender", length = 64) + @Column(name = "sender", length = 64, nullable = true) var hash: String? = "", - @Column(name = "sequence_number") + @Column(name = "sequence_number", nullable = true) var seqNo: Long? = null ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt index 122ada151b..a9e7e4885d 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt @@ -190,14 +190,14 @@ class P2PMessagingClient(val config: NodeConfiguration, @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}message_retry") class RetryMessage( @Id - @Column(name = "message_id", length = 64) + @Column(name = "message_id", length = 64, nullable = false) var key: Long = 0, @Lob - @Column + @Column(nullable = false) var message: ByteArray = EMPTY_BYTE_ARRAY, @Lob - @Column + @Column(nullable = false) var recipients: ByteArray = EMPTY_BYTE_ARRAY ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt index 90314a7555..d2caf00ed8 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NetworkMapUpdater.kt @@ -191,7 +191,7 @@ The node will shutdown now.""") val (update, signedNewNetParams) = requireNotNull(newNetworkParameters) { "Couldn't find parameters update for the hash: $parametersHash" } // We should check that we sign the right data structure hash. val newNetParams = signedNewNetParams.verifiedNetworkMapCert(networkMapClient.trustedRoot) - val newParametersHash = newNetParams.serialize().hash + val newParametersHash = signedNewNetParams.raw.hash if (parametersHash == newParametersHash) { // The latest parameters have priority. signedNewNetParams.serialize() diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBCheckpointStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBCheckpointStorage.kt index af277848ad..d448fb4c50 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DBCheckpointStorage.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBCheckpointStorage.kt @@ -38,11 +38,11 @@ class DBCheckpointStorage : CheckpointStorage { @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}checkpoints") class DBCheckpoint( @Id - @Column(name = "checkpoint_id", length = 64) + @Column(name = "checkpoint_id", length = 64, nullable = false) var checkpointId: String = "", @Lob - @Column(name = "checkpoint_value") + @Column(name = "checkpoint_value", nullable = false) var checkpoint: ByteArray = EMPTY_BYTE_ARRAY ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionMappingStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionMappingStorage.kt index b4ebdce00f..55110aa88d 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionMappingStorage.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionMappingStorage.kt @@ -42,10 +42,10 @@ class DBTransactionMappingStorage : StateMachineRecordedTransactionMappingStorag @javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}transaction_mappings") class DBTransactionMapping( @Id - @Column(name = "tx_id", length = 64) + @Column(name = "tx_id", length = 64, nullable = false) var txId: String = "", - @Column(name = "state_machine_run_id", length = 36) + @Column(name = "state_machine_run_id", length = 36, nullable = false) var stateMachineRunId: String = "" ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt index 2b64788804..cf8a94439d 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt @@ -46,11 +46,11 @@ class DBTransactionStorage(cacheSizeBytes: Long) : WritableTransactionStorage, S @Table(name = "${NODE_DATABASE_PREFIX}transactions") class DBTransaction( @Id - @Column(name = "tx_id", length = 64) + @Column(name = "tx_id", length = 64, nullable = false) var txId: String = "", @Lob - @Column(name = "transaction_value") + @Column(name = "transaction_value", nullable = false) var transaction: ByteArray = EMPTY_BYTE_ARRAY ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt index 789156c1a0..f6abc1a060 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt @@ -89,24 +89,24 @@ class NodeAttachmentService( @Table(name = "${NODE_DATABASE_PREFIX}attachments", indexes = [Index(name = "att_id_idx", columnList = "att_id")]) class DBAttachment( @Id - @Column(name = "att_id") + @Column(name = "att_id", nullable = false) var attId: String, - @Column(name = "content") + @Column(name = "content", nullable = false) @Lob var content: ByteArray, @Column(name = "insertion_date", nullable = false, updatable = false) var insertionDate: Instant = Instant.now(), - @Column(name = "uploader", updatable = false) + @Column(name = "uploader", updatable = false, nullable = true) var uploader: String? = null, - @Column(name = "filename", updatable = false) + @Column(name = "filename", updatable = false, nullable = true) var filename: String? = null, @ElementCollection - @Column(name = "contract_class_name") + @Column(name = "contract_class_name", nullable = false) @CollectionTable(name = "node_attchments_contracts", joinColumns = [(JoinColumn(name = "att_id", referencedColumnName = "att_id"))], foreignKey = ForeignKey(name = "FK__ctr_class__attachments")) var contractClassNames: List? = null diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt index 983edeb8a1..d90ab42547 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt @@ -40,10 +40,10 @@ class NodePropertiesPersistentStore(readPhysicalNodeId: () -> String, persistenc @Table(name = "${NODE_DATABASE_PREFIX}properties") class DBNodeProperty( @Id - @Column(name = "property_key") + @Column(name = "property_key", nullable = false) val key: String = "", - @Column(name = "property_value") + @Column(name = "property_value", nullable = true) var value: String? = "" ) : Serializable } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt index 3e5e486c17..368ec94a8a 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt @@ -116,8 +116,7 @@ class BFTNonValidatingNotaryService( fromPersistentEntity = { //TODO null check will become obsolete after making DB/JPA columns not nullable val txId = it.id.txId - ?: throw IllegalStateException("DB returned null SecureHash transactionId") - val index = it.id.index ?: throw IllegalStateException("DB returned null SecureHash index") + val index = it.id.index Pair( StateRef(txhash = SecureHash.parse(txId), index = index), SecureHash.parse(it.consumingTxHash) diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt index 71ac6a6678..748ad581b5 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt @@ -47,7 +47,7 @@ class PersistentUniquenessProvider(val clock: Clock) : UniquenessProvider, Singl @EmbeddedId val id: PersistentStateRef, - @Column(name = "consuming_transaction_id") + @Column(name = "consuming_transaction_id", nullable = false) val consumingTxHash: String ) : Serializable @@ -57,19 +57,20 @@ class PersistentUniquenessProvider(val clock: Clock) : UniquenessProvider, Singl class Request( @Id @GeneratedValue + @Column(nullable = true) val id: Int? = null, - @Column(name = "consuming_transaction_id") + @Column(name = "consuming_transaction_id", nullable = false) val consumingTxHash: String, - @Column(name = "requesting_party_name") + @Column(name = "requesting_party_name", nullable = false) var partyName: String, @Lob - @Column(name = "request_signature") + @Column(name = "request_signature", nullable = false) val requestSignature: ByteArray, - @Column(name = "request_timestamp") + @Column(name = "request_timestamp", nullable = false) var requestDate: Instant ) : Serializable @@ -91,8 +92,7 @@ class PersistentUniquenessProvider(val clock: Clock) : UniquenessProvider, Singl fromPersistentEntity = { //TODO null check will become obsolete after making DB/JPA columns not nullable val txId = it.id.txId - ?: throw IllegalStateException("DB returned null SecureHash transactionId") - val index = it.id.index ?: throw IllegalStateException("DB returned null SecureHash index") + val index = it.id.index Pair( StateRef(txhash = SecureHash.parse(txId), index = index), SecureHash.parse(it.consumingTxHash) diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt index 74662f5633..02bae2c566 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt @@ -75,8 +75,7 @@ class RaftUniquenessProvider( toPersistentEntityKey = { PersistentStateRef(it) }, fromPersistentEntity = { val txId = it.id.txId - ?: throw IllegalStateException("DB returned null SecureHash transactionId") - val index = it.id.index ?: throw IllegalStateException("DB returned null SecureHash index") + val index = it.id.index Pair( StateRef(txhash = SecureHash.parse(txId), index = index), Pair(it.index, SecureHash.parse(it.value) as SecureHash)) @@ -101,9 +100,9 @@ class RaftUniquenessProvider( class CommittedState( @EmbeddedId val id: PersistentStateRef, - @Column(name = "consuming_transaction_id") + @Column(name = "consuming_transaction_id", nullable = false) var value: String = "", - @Column(name = "raft_log_index") + @Column(name = "raft_log_index", nullable = false) var index: Long = 0 ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt index f59669e4e1..50e7995c1c 100644 --- a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt @@ -28,11 +28,11 @@ class ContractUpgradeServiceImpl : ContractUpgradeService, SingletonSerializeAsT @Table(name = "${NODE_DATABASE_PREFIX}contract_upgrades") class DBContractUpgrade( @Id - @Column(name = "state_ref", length = 96) + @Column(name = "state_ref", length = 96, nullable = false) var stateRef: String = "", /** refers to the UpgradedContract class name*/ - @Column(name = "contract_class_name") + @Column(name = "contract_class_name", nullable = false) var upgradedContractClassName: String = "" ) : Serializable diff --git a/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt b/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt index 8e83aeebe0..8acc247892 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/VaultSchema.kt @@ -47,19 +47,19 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio // TODO: create a distinct table to hold serialized state data (once DBTransactionStore is encrypted) /** refers to the X500Name of the notary a state is attached to */ - @Column(name = "notary_name") + @Column(name = "notary_name", nullable = false) var notary: Party, /** references a concrete ContractState that is [QueryableState] and has a [MappedSchema] */ - @Column(name = "contract_state_class_name") + @Column(name = "contract_state_class_name", nullable = false) var contractStateClassName: String, /** state lifecycle: unconsumed, consumed */ - @Column(name = "state_status") + @Column(name = "state_status", nullable = false) var stateStatus: Vault.StateStatus, /** refers to timestamp recorded upon entering UNCONSUMED state */ - @Column(name = "recorded_timestamp") + @Column(name = "recorded_timestamp", nullable = false) var recordedTime: Instant, /** refers to timestamp recorded upon entering CONSUMED state */ @@ -94,7 +94,7 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio /** * Represents a [LinearState] [UniqueIdentifier] */ - @Column(name = "external_id") + @Column(name = "external_id", nullable = true) var externalId: String?, @Column(name = "uuid", nullable = false) @@ -117,13 +117,13 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio @CollectionTable(name = "vault_fungible_states_parts", joinColumns = [(JoinColumn(name = "output_index", referencedColumnName = "output_index")), (JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"))], foreignKey = ForeignKey(name = "FK__fung_st_parts__fung_st")) - @Column(name = "participants") + @Column(name = "participants", nullable = true) var participants: MutableSet? = null, /** [OwnableState] attributes */ /** X500Name of owner party **/ - @Column(name = "owner_name") + @Column(name = "owner_name", nullable = true) var owner: AbstractParty, /** [FungibleAsset] attributes @@ -133,16 +133,16 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio */ /** Amount attributes */ - @Column(name = "quantity") + @Column(name = "quantity", nullable = false) var quantity: Long, /** Issuer attributes */ /** X500Name of issuer party **/ - @Column(name = "issuer_name") + @Column(name = "issuer_name", nullable = true) var issuer: AbstractParty, - @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE) + @Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false) @Type(type = "corda-wrapper-binary") var issuerRef: ByteArray ) : PersistentState() { @@ -159,13 +159,13 @@ object VaultSchemaV1 : MappedSchema(schemaFamily = VaultSchema.javaClass, versio class VaultTxnNote( @Id @GeneratedValue - @Column(name = "seq_no") + @Column(name = "seq_no", nullable = false) var seqNo: Int, - @Column(name = "transaction_id", length = 64) + @Column(name = "transaction_id", length = 64, nullable = false) var txId: String, - @Column(name = "note") + @Column(name = "note", nullable = false) var note: String ) : Serializable { constructor(txId: String, note: String) : this(0, txId, note) diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt index f402c4e35a..72addf9246 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkParametersReaderTest.kt @@ -16,6 +16,8 @@ import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.internal.exists import net.corda.core.internal.readObject +import net.corda.core.serialization.deserialize +import net.corda.core.utilities.days import net.corda.core.utilities.seconds import net.corda.node.internal.NetworkParametersReader import net.corda.nodeapi.internal.network.* @@ -33,6 +35,7 @@ import java.net.URL import java.nio.file.FileSystem import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNotNull class NetworkParametersReaderTest { @Rule @@ -83,4 +86,14 @@ class NetworkParametersReaderTest { val parameters = NetworkParametersReader(DEV_ROOT_CA.certificate, networkMapClient, baseDirectory).networkParameters assertThat(parameters).isEqualTo(fileParameters) } + + @Test + fun `serialized parameters compatibility`() { + // Network parameters file from before eventHorizon extension + val inputStream = javaClass.classLoader.getResourceAsStream("network-compatibility/network-parameters") + assertNotNull(inputStream) + val inByteArray: ByteArray = inputStream.readBytes() + val parameters = inByteArray.deserialize() + assertThat(parameters.verified().eventHorizon).isEqualTo(Int.MAX_VALUE.days) + } } \ No newline at end of file diff --git a/node/src/test/resources/network-compatibility/network-parameters b/node/src/test/resources/network-compatibility/network-parameters new file mode 100644 index 0000000000..7eac063459 Binary files /dev/null and b/node/src/test/resources/network-compatibility/network-parameters differ diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializer.kt index d37b42d1a7..3e10251372 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializer.kt @@ -130,7 +130,7 @@ abstract class EvolutionSerializer( this.resultsIndex = it.index } ?: if (!it.value.type.isMarkedNullable) { throw NotSerializableException( - "New parameter ${it.value.name} is mandatory, should be nullable for evolution to worK") + "New parameter ${it.value.name} is mandatory, should be nullable for evolution to work") } } return EvolutionSerializerViaConstructor(new.type, factory, readersAsSerialized, constructor, constructorArgs) diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV1.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV1.kt index 99eaee0214..4aee250fdc 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV1.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV1.kt @@ -48,7 +48,7 @@ object DummyLinearStateSchemaV1 : MappedSchema(schemaFamily = DummyLinearStateSc /** * UniqueIdentifier */ - @Column(name = "external_id") + @Column(name = "external_id", nullable = true) var externalId: String?, @Column(name = "uuid", nullable = false) @@ -58,16 +58,16 @@ object DummyLinearStateSchemaV1 : MappedSchema(schemaFamily = DummyLinearStateSc /** * Dummy attributes */ - @Column(name = "linear_string") + @Column(name = "linear_string", nullable = false) var linearString: String, - @Column(name = "linear_number") + @Column(name = "linear_number", nullable = false) var linearNumber: Long, - @Column(name = "linear_timestamp") + @Column(name = "linear_timestamp", nullable = false) var linearTimestamp: Instant, - @Column(name = "linear_boolean") + @Column(name = "linear_boolean", nullable = false) var linearBoolean: Boolean ) : PersistentState() } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV2.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV2.kt index 28a273614a..13f34b6496 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV2.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/vault/DummyLinearStateSchemaV2.kt @@ -34,13 +34,13 @@ object DummyLinearStateSchemaV2 : MappedSchema(schemaFamily = DummyLinearStateSc @CollectionTable(name = "dummy_linear_states_v2_parts", joinColumns = [(JoinColumn(name = "output_index", referencedColumnName = "output_index")), (JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"))]) override var participants: MutableSet? = null, - @Column(name = "linear_string") var linearString: String, + @Column(name = "linear_string", nullable = false) var linearString: String, - @Column(name = "linear_number") var linearNumber: Long, + @Column(name = "linear_number", nullable = false) var linearNumber: Long, - @Column(name = "linear_timestamp") var linearTimestamp: java.time.Instant, + @Column(name = "linear_timestamp", nullable = false) var linearTimestamp: java.time.Instant, - @Column(name = "linear_boolean") var linearBoolean: Boolean, + @Column(name = "linear_boolean", nullable = false) var linearBoolean: Boolean, @Transient val uid: UniqueIdentifier