>) ->
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";