diff --git a/build.gradle b/build.gradle index 1009ed2b26..fa654e1a18 100644 --- a/build.gradle +++ b/build.gradle @@ -343,7 +343,7 @@ tasks.named("dependencyUpdates").configure { } tasks.named("wrapper") { - gradleVersion = '8.2.1' + gradleVersion = '8.4' distributionType = Wrapper.DistributionType.BIN } diff --git a/cordapp-configuration/src/main/resources/net/corda/cordapp/cordapp-configuration.properties b/cordapp-configuration/src/main/resources/net/corda/cordapp/cordapp-configuration.properties index 3a3eb4408c..6ab1c6d3ac 100644 --- a/cordapp-configuration/src/main/resources/net/corda/cordapp/cordapp-configuration.properties +++ b/cordapp-configuration/src/main/resources/net/corda/cordapp/cordapp-configuration.properties @@ -13,6 +13,7 @@ Corda-ClientStartableFlow-Classes=IMPLEMENTS;net.corda.v5.application.flows.Clie Corda-InitiatedFlow-Classes=IMPLEMENTS;net.corda.v5.application.flows.ResponderFlow Corda-Subflow-Classes=IMPLEMENTS;net.corda.v5.application.flows.Subflow Corda-Token-Observer-Classes=IMPLEMENTS;net.corda.v5.ledger.utxo.observer.UtxoLedgerTokenStateObserver +Corda-Token-Observer-v2-Classes=IMPLEMENTS;net.corda.v5.ledger.utxo.observer.UtxoTokenTransactionStateObserver Corda-Ledger-Named-Query-Classes=IMPLEMENTS;net.corda.v5.ledger.utxo.query.VaultNamedQueryFactory Corda-Ledger-Vault-Json-Factory-Classes=IMPLEMENTS;net.corda.v5.ledger.utxo.query.json.ContractStateVaultJsonFactory diff --git a/data/avro-schema/build.gradle b/data/avro-schema/build.gradle index e6c6bfd02c..5708c8e9c0 100644 --- a/data/avro-schema/build.gradle +++ b/data/avro-schema/build.gradle @@ -15,6 +15,10 @@ dependencies { implementation("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") { because "required until new version of Avro available which updates Jackson" } + + implementation("org.apache.commons:commons-compress:$commonsCompressVersion") { + because "CVE-2023-42503, current version of Avro uses an outdated version" + } } implementation platform(project(':corda-api')) @@ -23,6 +27,13 @@ dependencies { compileOnly 'org.osgi:osgi.annotation' } +configurations.all { + resolutionStrategy { + // CVE-2023-42503, current version of Avro uses an outdated version + force "org.apache.commons:commons-compress:$commonsCompressVersion" + } +} + description 'Data Model Definitions' def generatedAvroDir = layout.buildDirectory.dir('generated-avro') diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/FlowTimeout.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/FlowTimeout.avsc new file mode 100644 index 0000000000..e11c023042 --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/FlowTimeout.avsc @@ -0,0 +1,20 @@ +{ + "type": "record", + "name": "FlowTimeout", + "namespace": "net.corda.data.flow", + "doc": "Represents of a flow timeout instruction.", + "fields": [ + { + "name": "checkpointStateKey", + "type": "string", + "doc": "Key for the state record that is storing the checkpoint." + }, + { + "name": "timeoutDateTime", + "type": { + "type": "long", + "logicalType": "timestamp-millis" + } + } + ] +} diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/FlowEvent.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/FlowEvent.avsc index e55a08d157..53b7fcb9b1 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/FlowEvent.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/FlowEvent.avsc @@ -11,7 +11,6 @@ "name": "payload", "type": [ "net.corda.data.flow.event.StartFlow", - "net.corda.data.flow.event.Wakeup", "net.corda.data.flow.output.FlowStatus", "net.corda.data.flow.event.SessionEvent", "net.corda.data.flow.event.external.ExternalEventResponse" diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/SessionEvent.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/SessionEvent.avsc index d40abd5746..980ad4a443 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/SessionEvent.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/SessionEvent.avsc @@ -50,8 +50,8 @@ { "name": "payload", "type": [ - "net.corda.data.flow.event.session.SessionInit", - "net.corda.data.flow.event.session.SessionConfirm", + "net.corda.data.flow.event.session.SessionCounterpartyInfoRequest", + "net.corda.data.flow.event.session.SessionCounterpartyInfoResponse", "net.corda.data.flow.event.session.SessionData", "net.corda.data.flow.event.session.SessionClose", "net.corda.data.flow.event.session.SessionError" diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/Wakeup.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/Wakeup.avsc deleted file mode 100644 index 0421ca665e..0000000000 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/Wakeup.avsc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "record", - "name": "Wakeup", - "namespace": "net.corda.data.flow.event", - "fields": [] -} - diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/mapper/ExecuteCleanup.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/mapper/ExecuteCleanup.avsc index c04b43197d..e5e1595715 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/mapper/ExecuteCleanup.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/mapper/ExecuteCleanup.avsc @@ -4,5 +4,13 @@ "docs": "When this event is processed the flow mapper state should be set to null", "namespace": "net.corda.data.flow.event.mapper", "fields": [ + { + "name": "ids", + "docs": "A list of IDs of mapper states that should be deleted", + "type": { + "type": "array", + "items": "string" + } + } ] } diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionConfirm.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionConfirm.avsc deleted file mode 100644 index d51b9f99a5..0000000000 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionConfirm.avsc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "record", - "name": "SessionConfirm", - "doc" : "Acknowledge to counterparty that the session has been confirmed and is ready to send and receive messages.", - "namespace": "net.corda.data.flow.event.session", - "fields": [] -} diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionCounterpartyInfoRequest.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionCounterpartyInfoRequest.avsc new file mode 100644 index 0000000000..99758c5d76 --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionCounterpartyInfoRequest.avsc @@ -0,0 +1,13 @@ +{ + "type": "record", + "name": "SessionCounterpartyInfoRequest", + "doc" : "Request counterparties flow session information. This includes the flow protocol version that they are running.", + "namespace": "net.corda.data.flow.event.session", + "fields": [ + { + "name": "sessionInit", + "type": "net.corda.data.flow.event.session.SessionInit", + "doc": "Contains information that can be used to start an initiated flow. Will be null for messages sent to the initiator. Will be null when initiated party is confirmed to be present to ensure out of order messages that arrive first contain this info." + } + ] +} diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionCounterpartyInfoResponse.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionCounterpartyInfoResponse.avsc new file mode 100644 index 0000000000..039e4d4e3a --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/flow/event/session/SessionCounterpartyInfoResponse.avsc @@ -0,0 +1,7 @@ +{ + "type": "record", + "name": "SessionCounterpartyInfoResponse", + "doc" : "Sent from initiated to initiating party to inform them which protocol version of the flow they are running.", + "namespace": "net.corda.data.flow.event.session", + "fields": [] +} diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/FindTransactionIdsAndStatuses.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/FindTransactionIdsAndStatuses.avsc new file mode 100644 index 0000000000..382a85cd6e --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/FindTransactionIdsAndStatuses.avsc @@ -0,0 +1,15 @@ +{ + "type": "record", + "name": "FindTransactionIdsAndStatuses", + "doc": "A request to fetch transaction IDs and their statuses.", + "namespace": "net.corda.data.ledger.persistence", + "fields": [ + { + "name": "ids", + "type": { + "type" : "array", + "items" : "string" + }, + "doc": "A list of the transaction IDs to fetch." + }] +} diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/FindUnconsumedVisibleExactStates.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/FindUnconsumedVisibleExactStates.avsc new file mode 100644 index 0000000000..1f192264c0 --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/FindUnconsumedVisibleExactStates.avsc @@ -0,0 +1,13 @@ +{ + "type": "record", + "name": "FindUnconsumedStatesByExactType", + "doc": "Retrieve the unconsumed visible states of specific type. This only retrieves exact type excluding its states of subclass unlike {@link FindUnconsumedStatesByType}. One of several types of ledger persistence request {@link LedgerPersistenceRequest}", + "namespace": "net.corda.data.ledger.persistence", + "fields": [ + { + "name": "stateClassName", + "type": "string", + "doc": "The fully qualified state class name" + } + ] +} diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/LedgerPersistenceRequest.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/LedgerPersistenceRequest.avsc index f45bde6967..cddfd596f0 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/LedgerPersistenceRequest.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/persistence/LedgerPersistenceRequest.avsc @@ -34,12 +34,14 @@ "net.corda.data.ledger.persistence.PersistTransactionIfDoesNotExist", "net.corda.data.ledger.persistence.FindTransaction", "net.corda.data.ledger.persistence.FindUnconsumedStatesByType", + "net.corda.data.ledger.persistence.FindUnconsumedStatesByExactType", "net.corda.data.ledger.persistence.ResolveStateRefs", "net.corda.data.ledger.persistence.UpdateTransactionStatus", "net.corda.data.persistence.FindWithNamedQuery", "net.corda.data.ledger.persistence.FindSignedGroupParameters", "net.corda.data.ledger.persistence.PersistSignedGroupParametersIfDoNotExist", - "net.corda.data.ledger.persistence.FindSignedLedgerTransaction" + "net.corda.data.ledger.persistence.FindSignedLedgerTransaction", + "net.corda.data.ledger.persistence.FindTransactionIdsAndStatuses" ] }, { diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenClaim.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenClaim.avsc index f4dc1ff974..d465d7453d 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenClaim.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenClaim.avsc @@ -9,6 +9,12 @@ "type": "string", "doc": "Unique identifier for the claim" }, + { + "name": "claimTimestamp", + "type": ["null", "long"], + "default": null, + "doc": "Timestamp of when the claim was made in epoc milliseconds" + }, { "name": "claimedTokenStateRefs", "type": { diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenForceClaimRelease.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenForceClaimRelease.avsc new file mode 100644 index 0000000000..3195849513 --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/data/TokenForceClaimRelease.avsc @@ -0,0 +1,18 @@ +{ + "type": "record", + "name": "TokenForceClaimRelease", + "namespace": "net.corda.data.ledger.utxo.token.selection.data", + "doc": "Forcibly removes the entire claim. No response is expected for this event type.", + "fields": [ + { + "name": "poolKey", + "type": "net.corda.data.ledger.utxo.token.selection.key.TokenPoolCacheKey", + "doc": "The key of the cache pool for the existing claim" + }, + { + "name": "claimId", + "type": "string", + "doc": "Unique identifier for the claim" + } + ] +} \ No newline at end of file diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/event/TokenPoolCacheEvent.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/event/TokenPoolCacheEvent.avsc index a3907c11cc..ddfc65e2a2 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/event/TokenPoolCacheEvent.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/ledger/utxo/token/selection/event/TokenPoolCacheEvent.avsc @@ -16,7 +16,8 @@ "net.corda.data.ledger.utxo.token.selection.data.TokenClaimRelease", "net.corda.data.ledger.utxo.token.selection.data.TokenLedgerChange", "net.corda.data.ledger.utxo.token.selection.data.TokenCachedSyncCheck", - "net.corda.data.ledger.utxo.token.selection.data.TokenBalanceQuery" + "net.corda.data.ledger.utxo.token.selection.data.TokenBalanceQuery", + "net.corda.data.ledger.utxo.token.selection.data.TokenForceClaimRelease" ], "doc": "Represents the specific type and data of inbound event" } diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/command/registration/mgm/DeclineRegistration.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/command/registration/mgm/DeclineRegistration.avsc index 4faf7f21d5..b230f05297 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/command/registration/mgm/DeclineRegistration.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/command/registration/mgm/DeclineRegistration.avsc @@ -6,8 +6,17 @@ "fields": [ { "name": "reason", - "doc": "Reason that the request was declined.", + "doc": "Reason that the request was declined. This contains data that will remain internal in the MGM's system for record keeping.", "type": "string" + }, + { + "name": "reasonForUser", + "doc": "Reason that the request was declined. This contains data that will be communicated to the user to provide context. If not specified, no reason will be communicated back to the user.", + "type": [ + "null", + "string" + ], + "default": null } ] } \ No newline at end of file diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/p2p/v2/SetOwnRegistrationStatus.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/p2p/v2/SetOwnRegistrationStatus.avsc index f58ed8ee4c..82030cf4fc 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/p2p/v2/SetOwnRegistrationStatus.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/p2p/v2/SetOwnRegistrationStatus.avsc @@ -16,6 +16,14 @@ "name": "newStatus", "doc": "The new registration status.", "type": "net.corda.data.membership.common.v2.RegistrationStatus" + }, + { + "name": "reason", + "doc": "The reason the registration request was moved to this status. Mostly relevant for switches to negative statuses (e.g. declined) to provide further context to the user on the underlying reason.", + "type": [ + "null", + "string" + ] } ] } \ No newline at end of file diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/CompletedCommandMetadata.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/CompletedCommandMetadata.avsc new file mode 100644 index 0000000000..7e2db13b08 --- /dev/null +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/CompletedCommandMetadata.avsc @@ -0,0 +1,18 @@ +{ + "type": "record", + "name": "CompletedCommandMetadata", + "namespace": "net.corda.data.membership.state", + "doc": "Metadata about a previously completed registration command.", + "fields": [ + { + "name": "index", + "doc": "An index which can be used to determine the order of previously completed registration commands.", + "type": "int" + }, + { + "name": "command", + "doc": "The name of the command which was completed.", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/RegistrationState.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/RegistrationState.avsc index 28a5d16297..be44b79a8e 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/RegistrationState.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/membership/state/RegistrationState.avsc @@ -21,6 +21,15 @@ "name": "mgm", "doc": "Holding identity of the MGM.", "type": "net.corda.data.identity.HoldingIdentity" + }, + { + "name": "previouslyCompletedCommands", + "doc": "A list of all the previously completed commands during registration. Can be used for idempotency in the case of message replays.", + "type": { + "type": "array", + "items": "net.corda.data.membership.state.CompletedCommandMetadata" + }, + "default": [] } ] } \ No newline at end of file diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/EntityResponse.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/EntityResponse.avsc index 0b3408ea0b..bd0c994fe6 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/EntityResponse.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/EntityResponse.avsc @@ -16,6 +16,12 @@ "name": "metadata", "doc": "Metadata returned from the execution of the persistence operation", "type": "net.corda.data.KeyValuePairList" + }, + { + "name": "resumePoint", + "doc": "Used by queries that support stable paging to return opaque data that indicates where the next page should resume from", + "type": ["null", "bytes"], + "default": null } ] } diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/FindWithNamedQuery.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/FindWithNamedQuery.avsc index abc6ed6d41..339a9c73c0 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/FindWithNamedQuery.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/persistence/FindWithNamedQuery.avsc @@ -1,7 +1,7 @@ { "type": "record", "name": "FindWithNamedQuery", - "doc": "Find entities matched by a named query. Parameters for the query may be specified. Pagination is supported, but there's no guarantee of consistency if the underlying data changes. The data will not be sorted in Corda; if the database returns an unpredictable order that must be handled by the caller. FindWithNamedQuery can be used to enforce ordering if required. Replies with {@link EntityResponse}", + "doc": "Find entities matched by a named query. Parameters for the query may be specified. Pagination is supported, but there's no guarantee of consistency if the underlying data changes and using offset-based pagination. The data will not be sorted in Corda; if the database returns an unpredictable order that must be handled by the caller. FindWithNamedQuery can be used to enforce ordering if required. Replies with {@link EntityResponse}", "namespace": "net.corda.data.persistence", "fields": [ { @@ -26,6 +26,12 @@ "name": "limit", "type": "int", "doc": "Limit number of rows in the output query results, after applying the offset. Use the maximum int value if you do not want a lower limit." + }, + { + "name": "resumePoint", + "type": ["null", "bytes"], + "default": null, + "doc": "When a query supports stable paging, contains opaque data telling the query where to resume from when making queries for subsequent pages." } ] } diff --git a/data/avro-schema/src/main/resources/avro/net/corda/data/virtualnode/VirtualNodeUpgradeRequest.avsc b/data/avro-schema/src/main/resources/avro/net/corda/data/virtualnode/VirtualNodeUpgradeRequest.avsc index 392c7383fa..a5e5493b72 100644 --- a/data/avro-schema/src/main/resources/avro/net/corda/data/virtualnode/VirtualNodeUpgradeRequest.avsc +++ b/data/avro-schema/src/main/resources/avro/net/corda/data/virtualnode/VirtualNodeUpgradeRequest.avsc @@ -17,6 +17,12 @@ "name": "actor", "type": "string", "doc": "ID of RPC user that requested the virtual node creation." + }, + { + "name": "forceUpgrade", + "type": "boolean", + "doc": "Whether this upgrade should be forced regardless of OperationInProgress.", + "default": false } ] } \ No newline at end of file diff --git a/data/avro-schema/src/test/kotlin/net/corda/data/ledger/utxo/token/selection/data/TokenClaimSchemaCompatibilityTest.kt b/data/avro-schema/src/test/kotlin/net/corda/data/ledger/utxo/token/selection/data/TokenClaimSchemaCompatibilityTest.kt new file mode 100644 index 0000000000..284468df53 --- /dev/null +++ b/data/avro-schema/src/test/kotlin/net/corda/data/ledger/utxo/token/selection/data/TokenClaimSchemaCompatibilityTest.kt @@ -0,0 +1,64 @@ +package net.corda.data.ledger.utxo.token.selection.data + +import org.apache.avro.Schema +import org.apache.avro.SchemaCompatibility +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class TokenClaimSchemaCompatibilityTest { + + @Test + fun `Token Claim schema changes between Corda 5_0 and 5_1 are compatible`() { + val oldSchemaJson = """ + { + "type": "record", + "name": "TokenClaim", + "namespace": "net.corda.data.ledger.utxo.token.selection.data", + "doc": "The set of tokens claimed by a query", + "fields": [ + { + "name": "claimId", + "type": "string", + "doc": "Unique identifier for the claim" + }, + { + "name": "claimedTokenStateRefs", + "type": { + "type": "array", + "items": "string" + }, + "default": [], + "doc": "Deprecated. The List of state refs for the claimed tokens" + }, + { + "name": "claimedTokens", + "type": { + "type": "array", + "items": "net.corda.data.ledger.utxo.token.selection.data.Token" + }, + "default": [], + "doc": "List of claimed tokens" + } + ] +} +""".trimIndent() + + val oldSchema = Schema.Parser() + .addTypes( + mapOf( + Token::class.java.name to Token.`SCHEMA$`, + ) + ) + .parse(oldSchemaJson) + + val newSchema = TokenClaim.`SCHEMA$` + + val compatibility = SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema) + + Assertions.assertEquals( + compatibility.type, + SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, + "Failed due to incompatible change. ${compatibility.description}" + ) + } +} \ No newline at end of file diff --git a/data/avro-schema/src/test/kotlin/net/corda/data/membership/command/registration/mgm/DeclineRegistrationCompatibilityTest.kt b/data/avro-schema/src/test/kotlin/net/corda/data/membership/command/registration/mgm/DeclineRegistrationCompatibilityTest.kt new file mode 100644 index 0000000000..130d61db8d --- /dev/null +++ b/data/avro-schema/src/test/kotlin/net/corda/data/membership/command/registration/mgm/DeclineRegistrationCompatibilityTest.kt @@ -0,0 +1,42 @@ +package net.corda.data.membership.command.registration.mgm + +import org.apache.avro.Schema +import org.apache.avro.SchemaCompatibility +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class DeclineRegistrationCompatibilityTest { + + @Test + fun `Changes in DeclineRegistration command between Corda 5_0 and 5_1 are compatible`() { + val oldSchemaJson = """ + { + "type": "record", + "name": "DeclineRegistration", + "namespace": "net.corda.data.membership.command.registration.mgm", + "doc": "Command issued when a member registration has been declined and needs to be updated to declined status.", + "fields": [ + { + "name": "reason", + "doc": "Reason that the request was declined. This contains data that will remain internal in the MGM's system for record keeping.", + "type": "string" + } + ] + } + """.trimIndent() + + val oldSchema = Schema.Parser() + .parse(oldSchemaJson) + + val newSchema = DeclineRegistration.`SCHEMA$` + + val compatibility = SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema) + + Assertions.assertEquals( + compatibility.type, + SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, + "Failed due to incompatible change. ${compatibility.description}" + ) + } + +} \ No newline at end of file diff --git a/data/avro-schema/src/test/kotlin/net/corda/data/membership/state/RegistrationStateTest.kt b/data/avro-schema/src/test/kotlin/net/corda/data/membership/state/RegistrationStateTest.kt new file mode 100644 index 0000000000..3032520184 --- /dev/null +++ b/data/avro-schema/src/test/kotlin/net/corda/data/membership/state/RegistrationStateTest.kt @@ -0,0 +1,56 @@ +package net.corda.data.membership.state + +import net.corda.data.identity.HoldingIdentity +import org.apache.avro.Schema +import org.apache.avro.SchemaCompatibility +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class RegistrationStateTest { + + @Test + fun `Changes in RegistrationState between Corda 5_0 and 5_1 are compatible`() { + val oldSchemaJson = """ + { + "type": "record", + "name": "RegistrationState", + "namespace": "net.corda.data.membership.state", + "doc": "State for a registration.", + "fields": [ + { + "name": "registrationId", + "doc": "UUID identifying this registration request", + "type": { + "type": "string", + "logicalType": "uuid" + } + }, + { + "name": "registeringMember", + "doc": "Holding identity of the registering member as provided during P2P communication. Used to verify the registration request.", + "type": "net.corda.data.identity.HoldingIdentity" + }, + { + "name": "mgm", + "doc": "Holding identity of the MGM.", + "type": "net.corda.data.identity.HoldingIdentity" + } + ] + } + """.trimIndent() + + val oldSchema = Schema.Parser() + .addTypes(mapOf(HoldingIdentity::class.java.name to HoldingIdentity.`SCHEMA$`)) + .parse(oldSchemaJson) + val newSchema = RegistrationState.`SCHEMA$` + + val compatibility = SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema) + + Assertions.assertEquals( + compatibility.type, + SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, + "Failed due to incompatible change. ${compatibility.description}" + ) + } + +} \ No newline at end of file diff --git a/data/avro-schema/src/test/kotlin/net/corda/data/virtualnode/VirtualNodeUpgradeRequestSchemaCompatibilityTest.kt b/data/avro-schema/src/test/kotlin/net/corda/data/virtualnode/VirtualNodeUpgradeRequestSchemaCompatibilityTest.kt new file mode 100644 index 0000000000..7899f7efdf --- /dev/null +++ b/data/avro-schema/src/test/kotlin/net/corda/data/virtualnode/VirtualNodeUpgradeRequestSchemaCompatibilityTest.kt @@ -0,0 +1,47 @@ +package net.corda.data.virtualnode + +import org.apache.avro.Schema +import org.apache.avro.SchemaCompatibility +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class VirtualNodeUpgradeRequestSchemaCompatibilityTest { + + @Test + fun `VirtualNodeUpgradeRequest schema changes between Corda 5_0 and 5_1 are compatible`() { + val schemaV50Json = """ + { + "type": "record", + "name": "VirtualNodeUpgradeRequest", + "namespace": "net.corda.data.virtualnode", + "fields": [ + { + "name": "virtualNodeShortHash", + "type": "string", + "doc": "Short hash of the virtual node / holding identity." + }, + { + "name": "cpiFileChecksum", + "type": "string", + "doc": "The checksum of the CPI file." + }, + { + "name": "actor", + "type": "string", + "doc": "ID of RPC user that requested the virtual node creation." + } + ] + } + """.trimIndent() + + val schemaV50 = Schema.Parser().parse(schemaV50Json) + val schemaV51 = VirtualNodeUpgradeRequest.`SCHEMA$` + + val compatibility = SchemaCompatibility.checkReaderWriterCompatibility(schemaV51, schemaV50) + Assertions.assertEquals( + compatibility.type, + SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, + "Failed due to incompatible change. ${compatibility.description}" + ) + } +} \ No newline at end of file diff --git a/data/config-schema/src/main/java/net/corda/schema/configuration/BootConfig.java b/data/config-schema/src/main/java/net/corda/schema/configuration/BootConfig.java index 34637fcd7e..de0f1452b0 100644 --- a/data/config-schema/src/main/java/net/corda/schema/configuration/BootConfig.java +++ b/data/config-schema/src/main/java/net/corda/schema/configuration/BootConfig.java @@ -35,4 +35,16 @@ private BootConfig() { public static final String BOOT_REST_TLS_CA_CRT_PATH = BOOT_REST + ".tls.ca.crt.path"; public static final String BOOT_SECRETS = "secrets"; + + public static final String BOOT_STATE_MANAGER = StateManagerConfig.STATE_MANAGER; + public static final String BOOT_STATE_MANAGER_TYPE = BOOT_STATE_MANAGER + ".type"; + public static final String BOOT_STATE_MANAGER_DB_USER = BOOT_STATE_MANAGER + ".database.user"; + public static final String BOOT_STATE_MANAGER_DB_PASS = BOOT_STATE_MANAGER + ".database.pass"; + public static final String BOOT_STATE_MANAGER_JDBC_URL = BOOT_STATE_MANAGER + ".database.jdbc.url"; + + public static final String BOOT_WORKER_SERVICE = "worker"; + public static final String CRYPTO_WORKER_REST_ENDPOINT = BOOT_WORKER_SERVICE + ".endpoints.crypto"; + public static final String VERIFICATION_WORKER_REST_ENDPOINT = BOOT_WORKER_SERVICE + ".endpoints.verification"; + public static final String UNIQUENESS_WORKER_REST_ENDPOINT = BOOT_WORKER_SERVICE + ".endpoints.uniqueness"; + public static final String PERSISTENCE_WORKER_REST_ENDPOINT = BOOT_WORKER_SERVICE + ".endpoints.persistence"; } diff --git a/data/config-schema/src/main/java/net/corda/schema/configuration/ConfigKeys.java b/data/config-schema/src/main/java/net/corda/schema/configuration/ConfigKeys.java index 7b7ec6b18a..a18dfda1b1 100644 --- a/data/config-schema/src/main/java/net/corda/schema/configuration/ConfigKeys.java +++ b/data/config-schema/src/main/java/net/corda/schema/configuration/ConfigKeys.java @@ -14,6 +14,7 @@ private ConfigKeys() { public static final String FLOW_CONFIG = "corda.flow"; public static final String MESSAGING_CONFIG = "corda.messaging"; public static final String EXTERNAL_MESSAGING_CONFIG = "corda.externalMessaging"; + public static final String STATE_MANAGER_CONFIG = "corda." + StateManagerConfig.STATE_MANAGER; public static final String UTXO_LEDGER_CONFIG = "corda.ledger.utxo"; public static final String P2P_LINK_MANAGER_CONFIG = "corda.p2p.linkManager"; public static final String P2P_GATEWAY_CONFIG = "corda.p2p.gateway"; diff --git a/data/config-schema/src/main/java/net/corda/schema/configuration/LedgerConfig.java b/data/config-schema/src/main/java/net/corda/schema/configuration/LedgerConfig.java index 21708fb450..c8867ed760 100644 --- a/data/config-schema/src/main/java/net/corda/schema/configuration/LedgerConfig.java +++ b/data/config-schema/src/main/java/net/corda/schema/configuration/LedgerConfig.java @@ -10,6 +10,7 @@ private LedgerConfig() { public static final String UTXO_TOKEN_PERIODIC_CHECK_BLOCK_SIZE = "tokens.periodCheckBlockSize"; public static final String UTXO_TOKEN_SEND_WAKEUP_MAX_RETRY_ATTEMPTS = "tokens.sendWakeUpMaxRetryAttempts"; public static final String UTXO_TOKEN_SEND_WAKEUP_MAX_RETRY_DELAY = "tokens.sendWakeUpMaxRetryDelay"; - public static final String UTXO_TOKEN_CACHED_TOKEN_PAGE_SIZE= "tokens.cachedTokenPageSize"; + public static final String UTXO_TOKEN_CACHED_TOKEN_PAGE_SIZE = "tokens.cachedTokenPageSize"; + public static final String UTXO_TOKEN_CLAIM_TIMEOUT_SECONDS = "tokens.claimTimeoutSeconds"; public static final String UTXO_BACKCHAIN_BATCH_SIZE = "backchain.batchSize"; } diff --git a/data/config-schema/src/main/java/net/corda/schema/configuration/MessagingConfig.java b/data/config-schema/src/main/java/net/corda/schema/configuration/MessagingConfig.java index de19bbdbbd..ff08267671 100644 --- a/data/config-schema/src/main/java/net/corda/schema/configuration/MessagingConfig.java +++ b/data/config-schema/src/main/java/net/corda/schema/configuration/MessagingConfig.java @@ -78,31 +78,4 @@ private Publisher() { * producers to stay under this limit when publishing messages. */ public static final String MAX_ALLOWED_MSG_SIZE = "maxAllowedMessageSize"; - - /** - * State Manager Configuration for connecting to the underlying persistent storage. - */ - public static final class StateManager { - private StateManager() { - } - - public static final String STATE_MANAGER = "stateManager"; - public static final String TYPE = STATE_MANAGER + ".type"; - - // Database Values - public static final String DB_PROPERTIES = STATE_MANAGER + ".database"; - public static final String JDBC_USER = DB_PROPERTIES + ".user"; - public static final String JDBC_PASS = DB_PROPERTIES + ".pass"; - - public static final String JDBC_URL = DB_PROPERTIES + ".jdbc.url"; - public static final String JDBC_DRIVER = DB_PROPERTIES + "jdbc.driver"; - public static final String JDBC_DRIVER_DIRECTORY = DB_PROPERTIES + ".jdbc.directory"; - public static final String JDBC_PERSISTENCE_UNIT_NAME = DB_PROPERTIES + ".jdbc.persistenceUnitName"; - public static final String JDBC_POOL_MAX_SIZE = DB_PROPERTIES + ".pool.maxSize"; - public static final String JDBC_POOL_MIN_SIZE = DB_PROPERTIES + ".pool.minSize"; - public static final String JDBC_POOL_IDLE_TIMEOUT_SECONDS = DB_PROPERTIES + ".pool.idleTimeoutSeconds"; - public static final String JDBC_POOL_MAX_LIFETIME_SECONDS = DB_PROPERTIES + ".pool.maxLifetimeSeconds"; - public static final String JDBC_POOL_KEEP_ALIVE_TIME_SECONDS = DB_PROPERTIES + ".pool.keepAliveTimeSeconds"; - public static final String JDBC_POOL_VALIDATION_TIMEOUT_SECONDS = DB_PROPERTIES + ".pool.validationTimeoutSeconds"; - } } diff --git a/data/config-schema/src/main/java/net/corda/schema/configuration/StateManagerConfig.java b/data/config-schema/src/main/java/net/corda/schema/configuration/StateManagerConfig.java new file mode 100644 index 0000000000..c09fc6336d --- /dev/null +++ b/data/config-schema/src/main/java/net/corda/schema/configuration/StateManagerConfig.java @@ -0,0 +1,30 @@ +package net.corda.schema.configuration; + +/** + * Configuration keys to access public parts of the configuration under the {@code corda.stateManager} key. + */ +public final class StateManagerConfig { + private StateManagerConfig() { + } + + public static final String STATE_MANAGER = "stateManager"; + + public static final String TYPE = "type"; + + // Database Configuration Values + public static final class Database { + public static final String DB_PROPERTIES = "database"; + public static final String JDBC_USER = DB_PROPERTIES + ".user"; + public static final String JDBC_PASS = DB_PROPERTIES + ".pass"; + + public static final String JDBC_URL = DB_PROPERTIES + ".jdbc.url"; + public static final String JDBC_DRIVER = DB_PROPERTIES + ".jdbc.driver"; + public static final String JDBC_DRIVER_DIRECTORY = DB_PROPERTIES + ".jdbc.directory"; + public static final String JDBC_POOL_MAX_SIZE = DB_PROPERTIES + ".pool.maxSize"; + public static final String JDBC_POOL_MIN_SIZE = DB_PROPERTIES + ".pool.minSize"; + public static final String JDBC_POOL_IDLE_TIMEOUT_SECONDS = DB_PROPERTIES + ".pool.idleTimeoutSeconds"; + public static final String JDBC_POOL_MAX_LIFETIME_SECONDS = DB_PROPERTIES + ".pool.maxLifetimeSeconds"; + public static final String JDBC_POOL_KEEP_ALIVE_TIME_SECONDS = DB_PROPERTIES + ".pool.keepAliveTimeSeconds"; + public static final String JDBC_POOL_VALIDATION_TIMEOUT_SECONDS = DB_PROPERTIES + ".pool.validationTimeoutSeconds"; + } +} diff --git a/data/config-schema/src/main/resources/net/corda/schema/configuration/flow/1.0/corda.flow.json b/data/config-schema/src/main/resources/net/corda/schema/configuration/flow/1.0/corda.flow.json index 8c0cfbfcd3..3e5331403d 100644 --- a/data/config-schema/src/main/resources/net/corda/schema/configuration/flow/1.0/corda.flow.json +++ b/data/config-schema/src/main/resources/net/corda/schema/configuration/flow/1.0/corda.flow.json @@ -54,6 +54,27 @@ "type": "object", "default": {}, "properties": { + "messageResendWindow": { + "description": "The length of time in milliseconds that Corda waits before resending unacknowledged flow session messages.", + "type": "integer", + "minimum": 1000, + "maximum": 2147483647, + "default": 120000 + }, + "heartbeatTimeout": { + "description": "The length of time in milliseconds that Corda waits when no message has been received from a counterparty before causing the session to error. This should be set at least 2 times larger than session.messageResendWindow.", + "type": "integer", + "minimum": 1000, + "maximum": 2147483647, + "default": 1800000 + }, + "missingCounterpartyTimeout": { + "description": "The length of time in milliseconds to wait when the counterparty can't be found in a member lookup before causing the session to error", + "type": "integer", + "minimum": 1000, + "maximum": 2147483647, + "default": 300000 + }, "timeout": { "description": "The length of time in milliseconds that Corda waits when no message has been received from a counterparty before causing the session to error.", "type": "integer", diff --git a/data/config-schema/src/main/resources/net/corda/schema/configuration/ledger.utxo/1.0/corda.ledger.utxo.json b/data/config-schema/src/main/resources/net/corda/schema/configuration/ledger.utxo/1.0/corda.ledger.utxo.json index 1c3a5a10d3..0b5b8fb91f 100644 --- a/data/config-schema/src/main/resources/net/corda/schema/configuration/ledger.utxo/1.0/corda.ledger.utxo.json +++ b/data/config-schema/src/main/resources/net/corda/schema/configuration/ledger.utxo/1.0/corda.ledger.utxo.json @@ -52,6 +52,12 @@ "type": "integer", "minimum": 0, "default": 1500 + }, + "claimTimeoutSeconds": { + "description": "Time in seconds before the claim will be automatically released (default 10 minutes)", + "type": "integer", + "minimum": 1, + "default": 600 } } }, diff --git a/data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/corda.messaging.json b/data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/corda.messaging.json index 72f0be5bb6..57eaf5e018 100644 --- a/data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/corda.messaging.json +++ b/data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/corda.messaging.json @@ -109,37 +109,6 @@ "default": 972800, "minimum": 512000, "maximum": 8388608 - }, - "stateManager": { - "description": "Connection details for the underlying persistent storage used by the out of process State Manager.", - "type": "object", - "properties": { - "type": { - "description": "The type of state manager implementation.", - "enum": [ - "DATABASE" - ] - }, - "additionalProperties": false - }, - "$comment": "Polymorphic state manager storage connection configuration. The valid section depends on which state manager implementation is in use.", - "allOf": [ - { - "if": { - "properties": {"type": {"const": "DATABASE"}}, - "required": ["type"] - }, - "then": { - "properties": { - "databaseProperties": { - "description": "Settings to connect to the state manager database.", - "$ref": "state-manager-db-properties.json" - } - }, - "required": ["type","databaseProperties"] - } - } - ] } }, "additionalProperties": false diff --git a/data/config-schema/src/main/resources/net/corda/schema/configuration/p2p.gateway/1.0/corda.p2p.gateway.json b/data/config-schema/src/main/resources/net/corda/schema/configuration/p2p.gateway/1.0/corda.p2p.gateway.json index 383ebd2c4e..e5380382de 100644 --- a/data/config-schema/src/main/resources/net/corda/schema/configuration/p2p.gateway/1.0/corda.p2p.gateway.json +++ b/data/config-schema/src/main/resources/net/corda/schema/configuration/p2p.gateway/1.0/corda.p2p.gateway.json @@ -8,7 +8,7 @@ "serversConfiguration": { "type": "array", "minItems": 1, - "description": "A list of HTTP servers that Corda listens to. The list is specified as an array of hostAddress, hostPort, and urlPath values. The hostAddress and hostPort pair must be unique for each server.", + "description": "A list of HTTP servers that Corda listens to. The list is specified as an array of hostAddress, hostPort, and urlPath values.", "default": [{ "hostAddress": "0.0.0.0", "hostPort": 8080, diff --git a/data/config-schema/src/main/resources/net/corda/schema/configuration/stateManager/1.0/corda.stateManager.json b/data/config-schema/src/main/resources/net/corda/schema/configuration/stateManager/1.0/corda.stateManager.json new file mode 100644 index 0000000000..ecca652728 --- /dev/null +++ b/data/config-schema/src/main/resources/net/corda/schema/configuration/stateManager/1.0/corda.stateManager.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://corda.r3.com/net/corda/schema/configuration/stateManager/1.0/corda.stateManager.json", + "title": "Corda State Manager Configuration Schema", + "description": "Configuration schema for the State Manager section. This configures the interactions of the workers with the underlying persistent storage used by the out of process State Manager.", + "type": "object", + "properties": { + "type": { + "description": "The type of state manager implementation.", + "enum": [ + "DATABASE" + ] + }, + "additionalProperties": false + }, + "$comment": "Polymorphic state manager storage connection configuration. The valid section depends on which state manager implementation is in use.", + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "DATABASE" + } + }, + "required": [ + "type" + ] + }, + "then": { + "properties": { + "databaseProperties": { + "description": "Settings to connect to the State Manager Database.", + "$ref": "stateManager-db-properties.json" + } + }, + "required": [ + "type", + "databaseProperties" + ] + } + } + ], + "additionalProperties": false +} diff --git a/data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/state-manager-db-properties.json b/data/config-schema/src/main/resources/net/corda/schema/configuration/stateManager/1.0/stateManager-db-properties.json similarity index 91% rename from data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/state-manager-db-properties.json rename to data/config-schema/src/main/resources/net/corda/schema/configuration/stateManager/1.0/stateManager-db-properties.json index a9d1bb7617..f0a89d0738 100644 --- a/data/config-schema/src/main/resources/net/corda/schema/configuration/messaging/1.0/state-manager-db-properties.json +++ b/data/config-schema/src/main/resources/net/corda/schema/configuration/stateManager/1.0/stateManager-db-properties.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", - "$id": "https://corda.r3.com/net/corda/schema/configuration/db/1.0/corda.db.json", + "$id": "https://corda.r3.com/net/corda/schema/configuration/stateManager/1.0/stateManager-db-properties.json", "title": "State Manager Database Configuration Schema", "description": "Configuration schema for the database section. Note that this configuration cannot be updated dynamically through the REST endpoint.", "type": "object", @@ -23,6 +23,11 @@ "type": "object", "default": {}, "properties": { + "url": { + "description": "The JDBC URL.", + "type": "string", + "default": "jdbc:postgresql://state-manager-db:5432/state_manager" + }, "driver": { "description": "The JDBC driver.", "type": "string", @@ -32,16 +37,6 @@ "description": "The directory that contains the JDBC drivers.", "type": "string", "default": "/opt/jdbc-driver" - }, - "url": { - "description": "The JDBC URL.", - "type": "string", - "default": "jdbc:postgresql://state-manager-db:5432/state_manager" - }, - "persistenceUnitName": { - "description": "The persistent unit name.", - "type": "string", - "default": "corda-state-manager" } }, "additionalProperties": false @@ -51,13 +46,13 @@ "type": "object", "default": {}, "properties": { - "max_size": { + "maxSize": { "description": "The maximum database pool size.", "type": "integer", "minimum": 1, "default": 10 }, - "min_size": { + "minSize": { "description": "The minimum database pool size. If left null will default to the `max_size` value.", "default": null, "anyOf": [ diff --git a/data/config-schema/src/test/kotlin/net/corda/schema/configuration/provider/impl/SchemaProviderConfigImplTest.kt b/data/config-schema/src/test/kotlin/net/corda/schema/configuration/provider/impl/SchemaProviderConfigImplTest.kt index eedb5e0d56..ec693d023c 100644 --- a/data/config-schema/src/test/kotlin/net/corda/schema/configuration/provider/impl/SchemaProviderConfigImplTest.kt +++ b/data/config-schema/src/test/kotlin/net/corda/schema/configuration/provider/impl/SchemaProviderConfigImplTest.kt @@ -12,6 +12,7 @@ import net.corda.schema.configuration.ConfigKeys.RECONCILIATION_CONFIG import net.corda.schema.configuration.ConfigKeys.REST_CONFIG import net.corda.schema.configuration.ConfigKeys.SANDBOX_CONFIG import net.corda.schema.configuration.ConfigKeys.SECRETS_CONFIG +import net.corda.schema.configuration.ConfigKeys.STATE_MANAGER_CONFIG import net.corda.schema.configuration.ConfigKeys.UTXO_LEDGER_CONFIG import net.corda.schema.configuration.provider.ConfigSchemaException import net.corda.v5.base.versioning.Version @@ -42,6 +43,7 @@ class SchemaProviderConfigImplTest { SANDBOX_CONFIG, RECONCILIATION_CONFIG, MEMBERSHIP_CONFIG, + STATE_MANAGER_CONFIG ) private val VERSIONS = listOf("1.0") @@ -99,4 +101,4 @@ class SchemaProviderConfigImplTest { provider.getSchemaFile(BAD_SCHEMA_FILE) } } -} \ No newline at end of file +} diff --git a/data/db-schema/src/main/java/net/corda/db/schema/DbSchema.java b/data/db-schema/src/main/java/net/corda/db/schema/DbSchema.java index a0956525a2..b1258ab5b1 100644 --- a/data/db-schema/src/main/java/net/corda/db/schema/DbSchema.java +++ b/data/db-schema/src/main/java/net/corda/db/schema/DbSchema.java @@ -38,6 +38,7 @@ private DbSchema() { public static final String VNODE_GROUP_PARAMETERS = "vnode_group_parameters"; public static final String VNODE_GROUP_APPROVAL_RULES = "vnode_group_approval_rules"; public static final String VNODE_PRE_AUTH_TOKENS = "vnode_pre_auth_tokens"; + public static final String VNODE_PERSISTENCE_REQUEST_ID_TABLE = "vnode_persistence_request_id"; public static final String LEDGER_CONSENSUAL_TRANSACTION_TABLE = "consensual_transaction"; public static final String LEDGER_CONSENSUAL_TRANSACTION_STATUS_TABLE = "consensual_transaction_status"; diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v1.0.xml b/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v1.0.xml index a0122f8ec2..392e3808d2 100644 --- a/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v1.0.xml +++ b/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v1.0.xml @@ -113,17 +113,6 @@ - - - - - - - - - - - diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v5.1.xml b/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v5.1.xml index cda0f02c7e..d8c6ce6275 100644 --- a/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v5.1.xml +++ b/data/db-schema/src/main/resources/net/corda/db/schema/config/migration/config-creation-v5.1.xml @@ -14,6 +14,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/rbac/db.changelog-master.xml b/data/db-schema/src/main/resources/net/corda/db/schema/rbac/db.changelog-master.xml index a13da5a56e..529f5b091c 100644 --- a/data/db-schema/src/main/resources/net/corda/db/schema/rbac/db.changelog-master.xml +++ b/data/db-schema/src/main/resources/net/corda/db/schema/rbac/db.changelog-master.xml @@ -3,4 +3,5 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> + \ No newline at end of file diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v1.0.xml b/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v1.0.xml index c0daab5257..6a109f460c 100644 --- a/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v1.0.xml +++ b/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v1.0.xml @@ -134,7 +134,7 @@ - + diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v5.1.xml b/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v5.1.xml new file mode 100644 index 0000000000..a355abd058 --- /dev/null +++ b/data/db-schema/src/main/resources/net/corda/db/schema/rbac/migration/rbac-creation-v5.1.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/db.changelog-master.xml b/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/db.changelog-master.xml index 3f2bcfa056..fa1edccb5f 100644 --- a/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/db.changelog-master.xml +++ b/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/db.changelog-master.xml @@ -5,6 +5,6 @@ - + diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/ledger-utxo-creation-v5.1.xml b/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/ledger-utxo-creation-v5.1.xml new file mode 100644 index 0000000000..b958807b00 --- /dev/null +++ b/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/ledger-utxo-creation-v5.1.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE utxo_transaction_output txo + SET + custom_representation = ( + SELECT custom_representation from utxo_visible_transaction_state vts + WHERE vts.transaction_id=txo.transaction_id + AND vts.group_idx=txo.group_idx + AND vts.leaf_idx=txo.leaf_idx + ), + consumed = ( + SELECT consumed from utxo_visible_transaction_state vts + WHERE vts.transaction_id=txo.transaction_id + AND vts.group_idx=txo.group_idx + AND vts.leaf_idx=txo.leaf_idx + ); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/vnode-vault-creation-v5.1.xml b/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/vnode-vault-creation-v5.1.xml index 18a92a0a8b..2e23034c07 100644 --- a/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/vnode-vault-creation-v5.1.xml +++ b/data/db-schema/src/main/resources/net/corda/db/schema/vnode-vault/migration/vnode-vault-creation-v5.1.xml @@ -6,5 +6,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/data/topic-schema/src/main/java/net/corda/schema/Schemas.java b/data/topic-schema/src/main/java/net/corda/schema/Schemas.java index 16c905b70e..9670061996 100644 --- a/data/topic-schema/src/main/java/net/corda/schema/Schemas.java +++ b/data/topic-schema/src/main/java/net/corda/schema/Schemas.java @@ -103,12 +103,21 @@ private Flow() { public static final String FLOW_MAPPER_EVENT_TOPIC = "flow.mapper.event"; public static final String FLOW_MAPPER_EVENT_STATE_TOPIC = getStateAndEventStateTopic(FLOW_MAPPER_EVENT_TOPIC); public static final String FLOW_MAPPER_EVENT_DLQ_TOPIC = getDLQTopic(FLOW_MAPPER_EVENT_TOPIC); + public static final String FLOW_INTEROP_EVENT_TOPIC = "flow.interop.event"; public static final String FLOW_INTEROP_EVENT_STATE_TOPIC = getStateAndEventStateTopic(FLOW_INTEROP_EVENT_TOPIC); public static final String FLOW_INTEROP_EVENT_DLQ_TOPIC = getDLQTopic(FLOW_INTEROP_EVENT_TOPIC); public static final String INTEROP_IDENTITY_TOPIC = "interop.identity"; public static final String INTEROP_GROUP_POLICY_TOPIC = "interop.group.policy"; + + public static final String FLOW_MAPPER_CLEANUP_TOPIC = "flow.mapper.cleanup"; + public static final String FLOW_TIMEOUT_TOPIC = "flow.timeout"; + public static final String FLOW_MAPPER_START = "flow.mapper.start"; + public static final String FLOW_MAPPER_SESSION_OUT = "flow.mapper.session.out"; + public static final String FLOW_MAPPER_SESSION_IN = "flow.mapper.session.in"; + public static final String FLOW_START = "flow.start"; + public static final String FLOW_SESSION = "flow.session"; } /** @@ -268,4 +277,16 @@ private VirtualNode() { public static final String CPI_UPLOAD_STATUS_TOPIC = "cpi.upload.status"; public static final String CPK_FILE_TOPIC = "cpk.file"; } + + public static final class ScheduledTask { + private ScheduledTask() {} + + public static final String SCHEDULED_TASK_TOPIC_DB_PROCESSOR = "scheduled.task.db.processor"; + public static final String SCHEDULED_TASK_NAME_DB_PROCESSOR = "deduplication-table-clean-up-task"; + public static final String SCHEDULED_TASK_TOPIC_MAPPER_PROCESSOR = "scheduled.task.mapper.processor"; + public static final String SCHEDULED_TASK_NAME_MAPPER_CLEANUP = "flow-mapper-state-cleanup"; + public static final String SCHEDULED_TASK_TOPIC_FLOW_PROCESSOR = "scheduled.task.flow.processor"; + public static final String SCHEDULED_TASK_NAME_SESSION_TIMEOUT = "flow-session-timeout"; + + } } diff --git a/data/topic-schema/src/main/resources/net/corda/schema/Flow.yaml b/data/topic-schema/src/main/resources/net/corda/schema/Flow.yaml index 00ffbd968f..345074d8da 100644 --- a/data/topic-schema/src/main/resources/net/corda/schema/Flow.yaml +++ b/data/topic-schema/src/main/resources/net/corda/schema/Flow.yaml @@ -136,3 +136,53 @@ topics: min.compaction.lag.ms: 60000 max.compaction.lag.ms: 604800000 min.cleanable.dirty.ratio: 0.5 + FlowMapperCleanupTopic: + name: flow.mapper.cleanup + consumers: + - flowMapper + producers: + - flowMapper + config: + FlowTimeoutTopic: + name: flow.timeout + consumers: + - flow + producers: + - flow + config: + FlowMapperStart: + name: flow.mapper.start + consumers: + - flowMapper + producers: + - rest + config: + FlowMapperSessionOut: + name: flow.mapper.session.out + consumers: + - flowMapper + producers: + - flow + config: + FlowMapperSessionIn: + name: flow.mapper.session.in + consumers: + - flowMapper + producers: + - link-manager + config: + FlowStart: + name: flow.start + consumers: + - flow + producers: + - flowMapper + config: + FlowSession: + name: flow.session + consumers: + - flow + producers: + - flowMapper + config: + diff --git a/data/topic-schema/src/main/resources/net/corda/schema/ScheduledTask.yaml b/data/topic-schema/src/main/resources/net/corda/schema/ScheduledTask.yaml new file mode 100644 index 0000000000..7a095d9faa --- /dev/null +++ b/data/topic-schema/src/main/resources/net/corda/schema/ScheduledTask.yaml @@ -0,0 +1,19 @@ +topics: + ScheduledTaskDbProcessorTopic: + name: scheduled.task.db.processor + consumers: + - db + producers: + - db + ScheduledTaskFlowMapperProcessorTopic: + name: scheduled.task.mapper.processor + consumers: + - flowMapper + producers: + - db + ScheduledTaskFlowProcessorTopic: + name: scheduled.task.flow.processor + consumers: + - flow + producers: + - db diff --git a/data/topic-schema/src/test/kotlin/net/corda/schema/SchemaTests.kt b/data/topic-schema/src/test/kotlin/net/corda/schema/SchemaTests.kt index 2cc3a013fc..01b32f108a 100644 --- a/data/topic-schema/src/test/kotlin/net/corda/schema/SchemaTests.kt +++ b/data/topic-schema/src/test/kotlin/net/corda/schema/SchemaTests.kt @@ -75,9 +75,9 @@ class SchemaTests { yamlFileData.forEach { (fileName: String, topics: Map>) -> println("Testing: $fileName") val potentialClass = fileName.substringBeforeLast(".") - val yamlTopicNames = topics["topics"]!!.toMap().map { it.value["name"] } + val yamlTopicNames = topics["topics"]!!.toMap().map { it.value["name"].toString() } val kotlinTopicNames = memberMap[potentialClass] - assertThat(yamlTopicNames).containsExactlyInAnyOrderElementsOf(kotlinTopicNames) + assertThat(kotlinTopicNames).containsAll(yamlTopicNames) } } } diff --git a/gradle.properties b/gradle.properties index 7ae9d103b1..314a40f30f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,8 +11,8 @@ cordaProductVersion = 5.1.0-INTEROP ## a per module property in which case module versions can change independently. ## IMPORTANT: ## The interop feature branches track api revisions separately to the mainline branch. -## API version of last merge from corda mainline: 19 -cordaApiRevision = 22 +## API version of last merge from corda mainline: 32 +cordaApiRevision = 23 # Main kotlinVersion = 1.8.21 @@ -44,7 +44,8 @@ slf4jVersion = 1.7.36 # Main implementation dependencies avroGradlePluginVersion=1.3.0 -avroVersion = 1.11.2 +avroVersion = 1.11.3 +commonsCompressVersion = 1.24.0 bouncycastleVersion = 1.73 grgitPluginVersion = 5.2.0 taskTreePluginVersion = 2.1.1 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cd..7f93135c49 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9f4197d5f4..3fa8f862f7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca147..1aa94a4269 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -201,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/UtxoLedgerService.java b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/UtxoLedgerService.java index 1603f3d86e..aa844829df 100644 --- a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/UtxoLedgerService.java +++ b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/UtxoLedgerService.java @@ -87,7 +87,14 @@ public interface UtxoLedgerService { UtxoFilteredTransactionBuilder filterSignedTransaction(@NotNull UtxoSignedTransaction transaction); /** - * Finds unconsumed states of the specified {@link ContractState} type in the vault. + * Finds unconsumed states that are concrete implementations or subclasses of {@code type}. + *

+ * Only use this method if subclasses of {@code type} must be returned. + *

+ * Use {@link #findUnconsumedStatesByExactType(Class)} to return exact instances of the input {@code type}. + * This method is more performant than {@link #findUnconsumedStatesByType(Class)}. + *

+ * Use {@link #query(String, Class)} for a more performant method of retrieving subclasses of a specified type. * * @param The underlying {@link ContractState} type. * @param type The {@link ContractState} type to find in the vault. @@ -97,6 +104,17 @@ public interface UtxoLedgerService { @Suspendable List> findUnconsumedStatesByType(@NotNull Class type); + /** + * Finds unconsumed states of the specified {@link ContractState} type in the vault. + * + * @param The underlying {@link ContractState} type. + * @param type The {@link ContractState} type to find in the vault. + * @return Returns a {@link List} of {@link StateAndRef} of unconsumed states of the specified type, or an empty list if no states could be found. + */ + @NotNull + @Suspendable + List> findUnconsumedStatesByExactType(@NotNull Class type); + /** * Verifies, signs, collects signatures, records and broadcasts a {@link UtxoSignedTransaction} to participants and observers. * diff --git a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/TokenStateObserverContext.java b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/TokenStateObserverContext.java new file mode 100644 index 0000000000..66c1e5340f --- /dev/null +++ b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/TokenStateObserverContext.java @@ -0,0 +1,28 @@ +package net.corda.v5.ledger.utxo.observer; + +import net.corda.v5.application.crypto.DigestService; +import net.corda.v5.ledger.utxo.ContractState; +import net.corda.v5.ledger.utxo.StateAndRef; +import org.jetbrains.annotations.NotNull; + +/** + * Represents the context in which the token is being generated and provides services that might be required. + */ +public interface TokenStateObserverContext { + + /** + * Gets the {@link StateAndRef} of the transaction which is responsible for generating the new tokens. + * + * @return Returns the {@link StateAndRef}. + */ + @NotNull + StateAndRef getStateAndRef(); + + /** + * Gets the {@link DigestService} which provides hashing capabilities. + * + * @return Returns a {@link DigestService}. + */ + @NotNull + DigestService getDigestService(); +} diff --git a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoLedgerTokenStateObserver.java b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoLedgerTokenStateObserver.java index fae1aebb33..c83da84acd 100644 --- a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoLedgerTokenStateObserver.java +++ b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoLedgerTokenStateObserver.java @@ -65,6 +65,7 @@ * } * } */ +@Deprecated(since = "5.1", forRemoval = true) public interface UtxoLedgerTokenStateObserver { /** diff --git a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoTokenTransactionStateObserver.java b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoTokenTransactionStateObserver.java new file mode 100644 index 0000000000..452c8d6298 --- /dev/null +++ b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/observer/UtxoTokenTransactionStateObserver.java @@ -0,0 +1,90 @@ +package net.corda.v5.ledger.utxo.observer; + +import net.corda.v5.ledger.utxo.ContractState; +import net.corda.v5.ledger.utxo.token.selection.TokenSelection; +import org.jetbrains.annotations.NotNull; + +/** + * Defines a mechanism to observe produced contract states of type {@link T} when they are committed to the ledger. + *

+ * Users should implement this interface for any states that need to be selectable via the {@link TokenSelection} API. + *

+ * The Corda platform will discover and invoke implementations of this interface for all produced states that match + * the type specified by {@link UtxoTokenTransactionStateObserver#getStateType()}. + *

+ * Example usage: + *

    + *
  • Java:
    {@code
    + * public class ExampleStateJ implements ContractState {
    + * public List participants;
    + * public SecureHash issuer;
    + * public String currency;
    + * public BigDecimal amount;
    + *
    + * @NotNull
    + * @Override public List getParticipants() {
    + * return participants;
    + * }
    + * }
    + *
    + * public class UtxoTokenTransactionStateObserverJavaExample implements UtxoTokenTransactionStateObserver {
    + * @NotNull
    + * @Override public Class getStateType() {
    + * return ExampleStateJ.class;
    + * }
    + * @NotNull
    + * @Override public UtxoToken onCommit(
    + * @NotNull TokenStateObserverContext context,
    + * )
    + * {
    + * return new UtxoToken(
    + * new UtxoTokenPoolKey(ExampleStateK.class.getName(),
    + * context.getStateAndRef().getState().getContractState().issuer,
    + * context.getStateAndRef().getState().getContractState().currency),
    + * context.getStateAndRef().getState().getContractState().amount,
    + * new UtxoTokenFilterFields()
    + * );
    + * }
    + * }
    + * }
  • + *
  • Kotlin:
    {@code
    + * data class ExampleStateK(
    + * override val participants: List,
    + * val issuer: SecureHash,
    + * val currency: String,
    + * val amount: BigDecimal
    + * ) : ContractState
    + *
    + * class UtxoTokenTransactionStateObserverKotlinExample : UtxoTokenTransactionStateObserver {
    + *
    + * override val stateType = ExampleStateK::class.java
    + *
    + * override fun onCommit(context: StateAndRef): UtxoToken {
    + * return UtxoToken(
    + * UtxoTokenPoolKey(ExampleStateK::class.java.name, context.stateAndRef.state.contractState.issuer, context.stateAndRef.state.contractState.currency),
    + * context.stateAndRef.state.contractState.amount,
    + * UtxoTokenFilterFields()
    + * )
    + * }
    + * }
    + * }
+ */ +public interface UtxoTokenTransactionStateObserver { + + /** + * Gets the {@link ContractState} type that the current observer is intended for. + * + * @return Returns the {@link ContractState} type that the current observer is intended for. + */ + @NotNull + Class getStateType(); + + /** + * The action to be performed when a {@link ContractState} of type {@link T} is committed to the ledger. + * + * @param context The {@link TokenStateObserverContext} in which the token is being generated. + * @return Returns a {@link UtxoToken}. + */ + @NotNull + UtxoToken onCommit(@NotNull TokenStateObserverContext context); +} diff --git a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenClaim.java b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenClaim.java index 747712b54f..aa36b34d6f 100644 --- a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenClaim.java +++ b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenClaim.java @@ -11,15 +11,8 @@ * Defines a claimed set of tokens returned by a call to {@link TokenSelection#tryClaim(TokenClaimCriteria)}. *

* The claimed {@link ClaimedToken} list is exclusively locked by the flow that made the claim and are - * unavailable to any other flows. - *

- * Once a flow has either spent some or all of the claimed tokens, it should call {@link TokenClaim#useAndRelease(List)} - * to notify the cache which tokens were used. - *

- * Any unused tokens will be released and made available to other flows. - *

- * If the flow does not call {@link TokenClaim#useAndRelease(List)}, the tokens will remain locked until the cache - * receives a consumed notification from the vault or the claim timeout elapses. + * unavailable to any other flows. Any unconsumed token that has been claimed by the flow is released and made + * available to other flows once the flow terminates either successfully or unsuccessfully. */ @DoNotImplement public interface TokenClaim { @@ -34,9 +27,12 @@ public interface TokenClaim { /** * Removes any used tokens from the cache and unlocks any remaining tokens for other flows to claim. + * This method is now deprecated. Claimed tokens are now managed differently which makes the method + * irrelevant. From release 5.1, nothing will happen if the method is called. * * @param usedTokensRefs The {@link List} of {@link StateRef}s to mark as used. */ @Suspendable + @Deprecated(since = "5.1", forRemoval = true) void useAndRelease(@NotNull List usedTokensRefs); } diff --git a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenSelection.java b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenSelection.java index 79d3e46f81..d986a99224 100644 --- a/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenSelection.java +++ b/ledger/ledger-utxo/src/main/java/net/corda/v5/ledger/utxo/token/selection/TokenSelection.java @@ -51,11 +51,7 @@ public interface TokenSelection { * // take alternative action. * } else { * // Tokens we successfully claimed and can now be spent. - * val spentTokenRefs = spendTokens(claim.claimedTokens) - * - * // Release the claim by notifying the cache which tokens where spent. Any unspent - * // tokens will be released for other flows to claim. - * claim.useAndRelease(spentTokenRefs!!) + * spendTokens(claim.claimedTokens) * } * * return "Done" @@ -83,11 +79,7 @@ public interface TokenSelection { * // take alternative action. * } else { * // Tokens we successfully claimed and can now be spent. - * List spentTokenRefs = spendTokens(claim.getClaimedTokens()); - * - * // Release the claim by notifying the cache which tokens where spent. Any unspent - * // tokens will be released for other flows to claim. - * claim.useAndRelease(spentTokenRefs); + * spendTokens(claim.getClaimedTokens()); * } * * return "Done";