From d1e75cbe16929715c443436e41efd511c6bca2d9 Mon Sep 17 00:00:00 2001
From: owenstanford <owen.stanford@r3.com>
Date: Fri, 22 Sep 2023 10:23:12 +0100
Subject: [PATCH] CORE-15396 Add support for an expiry timeout on a token
 claim, this is to support automatic cleanup of orphaned claims.

---
 .../utxo/token/selection/data/TokenClaim.avsc |  6 ++
 .../data/TokenClaimSchemaCompatibilityTest.kt | 64 +++++++++++++++++++
 .../schema/configuration/LedgerConfig.java    |  3 +-
 .../ledger.utxo/1.0/corda.ledger.utxo.json    |  6 ++
 4 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 data/avro-schema/src/test/kotlin/net/corda/data/ledger/utxo/token/selection/data/TokenClaimSchemaCompatibilityTest.kt

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/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/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/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
         }
       }
     },