diff --git a/apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/CryptoHashEquivalenceIntegrationTest.scala b/apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/CryptoHashEquivalenceIntegrationTest.scala new file mode 100644 index 0000000000..ccb86e5c7e --- /dev/null +++ b/apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/CryptoHashEquivalenceIntegrationTest.scala @@ -0,0 +1,273 @@ +package org.lfdecentralizedtrust.splice.integration.tests + +import com.daml.ledger.javaapi.data.{ + CreatedEvent, + CreateCommand, + DamlList, + DamlRecord, + ExerciseCommand, + ExercisedEvent, + Identifier, + Party, + Text, + Value, +} +import com.digitalasset.canton.resource.DbStorage +import com.digitalasset.canton.topology.PartyId +import com.digitalasset.daml.lf.data.Ref +import org.lfdecentralizedtrust.splice.integration.EnvironmentDefinition +import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.IntegrationTest +import org.lfdecentralizedtrust.splice.util.{DarUtil, WalletTestUtil} +import slick.jdbc.canton.ActionBasedSQLInterpolation.Implicits.actionBasedSQLInterpolationCanton + +import java.io.File +import scala.collection.mutable +import scala.jdk.CollectionConverters.* + +/** Equivalence test: Daml (real participant) == SQL (scan Postgres). + * + * Validates that the plpgsql hash functions produce identical results + * to the Daml CryptoHash module. Daml is the authority. + * + * Uses a shared environment so the dar is uploaded and proxy created once, + * then each hash function gets its own test. + */ +@org.lfdecentralizedtrust.splice.util.scalatesttags.NoDamlCompatibilityCheck +class CryptoHashEquivalenceIntegrationTest extends IntegrationTest with WalletTestUtil { + + import CryptoHashEquivalenceIntegrationTest.* + + override def environmentDefinition: SpliceEnvironmentDefinition = + EnvironmentDefinition + .simpleTopology1Sv(this.getClass.getSimpleName) + .withManualStart + + "CryptoHash equivalence (Daml == SQL)" should { + + "set up environment" in { implicit env => + startAllSync(sv1Backend) + svParty = sv1Backend.getDsoInfo().svParty + svDb = sv1Backend.appState.storage + + clue("Upload dar and create CryptoHashProxy") { + sv1Backend.participantClient.upload_dar_unless_exists(darPath) + val createArgs = new DamlRecord( + java.util.List.of( + new DamlRecord.Field("owner", new Party(svParty.toProtoPrimitive)) + ) + ) + val createTx = + sv1Backend.participantClientWithAdminToken.ledger_api_extensions.commands + .submitJava( + actAs = Seq(svParty), + commands = Seq(new CreateCommand(templateId, createArgs)), + ) + proxyContractId = createTx.getEvents.asScala + .collectFirst { case ce: CreatedEvent => ce.getContractId } + .getOrElse(fail("No CreatedEvent from CryptoHashProxy create")) + } + } + + allTestCaseDefs.foreach { tcDef => + tcDef.description in { implicit env => + val damlHash = clue("Daml") { exerciseDaml(tcDef.op) } + intermediates(tcDef.description) = damlHash + clue("SQL should match Daml") { + val sqlHash = svDb + .query( + sql"""select #${toSqlExpr(tcDef.op, resolveRef)}""".as[String].head, + "test.sqlHash", + ) + .futureValueUS + sqlHash shouldBe damlHash + } + } + } + } + + /** Exercise a Daml choice and return the Text result. */ + private def exerciseDaml(op: HashOp)(implicit env: FixtureParam): String = { + val (choiceName, choiceArg) = toDamlChoiceAndArg(op, resolveRef) + val cmd = new ExerciseCommand(templateId, proxyContractId, choiceName, choiceArg) + val tx = sv1Backend.participantClientWithAdminToken.ledger_api_extensions.commands + .submitJava( + actAs = Seq(svParty), + commands = Seq(cmd), + ) + tx.getEventsById.values.asScala + .collectFirst { case ex: ExercisedEvent => + ex.getExerciseResult match { + case t: Text => t.getValue + case other => + throw new IllegalStateException( + s"Expected Text result but got ${other.getClass.getSimpleName}" + ) + } + } + .getOrElse(throw new IllegalStateException("No ExercisedEvent in transaction")) + } + + private def resolveRef(ref: HashRef): String = ref match { + case Lit(v) => v + case IntermediateRef(name) => + intermediates.getOrElse( + name, + throw new IllegalStateException(s"Intermediate '$name' not found"), + ) + } + + // Progressive map: each test stores its Daml result for later tests to reference + private val intermediates: mutable.Map[String, String] = mutable.Map.empty + + private var svParty: PartyId = _ + private var proxyContractId: String = _ + private var svDb: DbStorage = _ + +} + +object CryptoHashEquivalenceIntegrationTest { + + // -- Package discovery ------------------------------------------------------ + + private val darPath = "daml/splice-amulet-test/.daml/dist/splice-amulet-test-current.dar" + private val moduleName = "Splice.Testing.CryptoHashProxy" + + private val packageId: String = { + val dar = DarUtil.readDar(new File(darPath)) + val modName = Ref.ModuleName.assertFromString(moduleName) + dar.all + .collectFirst { case (pkgId, pkg) if pkg.modules.contains(modName) => pkgId } + .getOrElse(sys.error(s"Could not find package containing $moduleName")) + .toString + } + + private val templateId = new Identifier(packageId, moduleName, "CryptoHashProxy") + + // -- HashRef: symbolic references to intermediate hash values --------------- + + sealed trait HashRef + case class Lit(value: String) extends HashRef + case class IntermediateRef(name: String) extends HashRef + + // -- HashOp: test case operations (may contain HashRef) --------------------- + + sealed trait HashOp + case class HashText(value: String) extends HashOp + case class HashList(elems: Seq[HashRef]) extends HashOp + case class HashVariant(tag: String, fields: Seq[HashRef]) extends HashOp + case class HashMintingAllowance(provider: String, amount: String) extends HashOp + case class HashBatchOfMintingAllowances(hashes: Seq[HashRef]) extends HashOp + case class HashBatchOfBatches(hashes: Seq[HashRef]) extends HashOp + + case class TestCaseDef(description: String, op: HashOp) + + // -- Derive Daml choice + arg from HashOp ---------------------------------- + + private def text(s: String): Value = new Text(s) + private def textList(ss: Seq[String]): Value = + DamlList.of(ss.map(s => new Text(s): Value).asJava) + private def record(fields: (String, Value)*): Value = + new DamlRecord(fields.map { case (k, v) => new DamlRecord.Field(k, v) }.asJava) + + def toDamlChoiceAndArg(op: HashOp, r: HashRef => String): (String, Value) = op match { + case HashText(v) => + ("CryptoHashProxy_HashText", record("input" -> text(v))) + case HashList(elems) => + ("CryptoHashProxy_HashList", record("elems" -> textList(elems.map(r)))) + case HashVariant(tag, fields) => + ( + "CryptoHashProxy_HashVariant", + record("tag" -> text(tag), "fields" -> textList(fields.map(r))), + ) + case HashMintingAllowance(provider, amount) => + ( + "CryptoHashProxy_HashMintingAllowance", + record("provider" -> text(provider), "amount" -> text(amount)), + ) + case HashBatchOfMintingAllowances(hashes) => + ( + "CryptoHashProxy_HashBatchOfMintingAllowances", + record("allowanceHashes" -> textList(hashes.map(r))), + ) + case HashBatchOfBatches(hashes) => + ("CryptoHashProxy_HashBatchOfBatches", record("childHashes" -> textList(hashes.map(r)))) + } + + // -- Derive SQL expression from HashOp ------------------------------------- + + private def escapeSql(s: String): String = s.replace("'", "''") + private def sqlArray(elems: Seq[String]): String = + s"ARRAY[${elems.map(e => s"'$e'").mkString(", ")}]::text[]" + + def toSqlExpr(op: HashOp, r: HashRef => String): String = op match { + case HashText(v) => + s"daml_crypto_hash_text('${escapeSql(v)}')" + case HashList(elems) => + s"daml_crypto_hash_list(${sqlArray(elems.map(r))})" + case HashVariant(tag, fields) => + s"daml_crypto_hash_variant('${escapeSql(tag)}', ${sqlArray(fields.map(r))})" + case HashMintingAllowance(provider, amount) => + s"hash_minting_allowance('${escapeSql(provider)}', '${escapeSql(amount)}')" + case HashBatchOfMintingAllowances(hashes) => + s"hash_batch_of_minting_allowances(${sqlArray(hashes.map(r))})" + case HashBatchOfBatches(hashes) => + s"hash_batch_of_batches(${sqlArray(hashes.map(r))})" + } + + // -- Test case definitions (fully static) ----------------------------------- + + // Test cases are defined statically using HashRef (Lit/IntermediateRef) to + // reference intermediate hashes by name. Each test resolves its refs from + // a shared map populated progressively as earlier tests run. + // + // Order matters: intermediates must precede composites that reference them. + val allTestCaseDefs: Seq[TestCaseDef] = Seq( + // Primitive text hashes — used as intermediates by composite cases + TestCaseDef("hAlice", HashText("alice::provider")), + TestCaseDef("h10", HashText("10.0")), + TestCaseDef("hOnly", HashText("only")), + TestCaseDef("h1", HashText("1")), + TestCaseDef("hx", HashText("x")), + + // Minting allowance hashes — used as intermediates by batch cases + TestCaseDef("maAlice", HashMintingAllowance("alice::provider", "10.0000000000")), + TestCaseDef("maBob", HashMintingAllowance("bob::provider", "0")), + TestCaseDef("maAlice5", HashMintingAllowance("alice::provider", "5.0")), + TestCaseDef("maBob3", HashMintingAllowance("bob::provider", "3.0")), + // Batch hashes — used as intermediates by batch-of-batches + TestCaseDef("leaf1", HashBatchOfMintingAllowances(Seq(IntermediateRef("maAlice5")))), + TestCaseDef("leaf2", HashBatchOfMintingAllowances(Seq(IntermediateRef("maBob3")))), + + // Independent cases (no intermediate references) + TestCaseDef("hash of 'hello'", HashText("hello")), + TestCaseDef("hash of empty string", HashText("")), + TestCaseDef("hashList on empty array", HashList(Seq.empty)), + + // Composite cases using intermediate hashes + TestCaseDef( + "hashList with two elements", + HashList(Seq(IntermediateRef("hAlice"), IntermediateRef("h10"))), + ), + TestCaseDef("hashList on single element", HashList(Seq(IntermediateRef("hOnly")))), + TestCaseDef( + "hashVariant with tag and one field", + HashVariant("TestTag", Seq(IntermediateRef("hAlice"))), + ), + TestCaseDef( + "hashRecord [hash 1, hash 'x']", + HashList(Seq(IntermediateRef("h1"), IntermediateRef("hx"))), + ), + TestCaseDef( + "hashVariant 'V1' [hash 1, hash 'x']", + HashVariant("V1", Seq(IntermediateRef("h1"), IntermediateRef("hx"))), + ), + TestCaseDef( + "hash_batch_of_minting_allowances with two", + HashBatchOfMintingAllowances(Seq(IntermediateRef("maAlice"), IntermediateRef("maBob"))), + ), + TestCaseDef( + "hash_batch_of_batches with two leaves", + HashBatchOfBatches(Seq(IntermediateRef("leaf1"), IntermediateRef("leaf2"))), + ), + ) +} diff --git a/apps/common/src/main/resources/db/migration/canton-network/postgres/stable/V065__app_reward_hash_functions.sql b/apps/common/src/main/resources/db/migration/canton-network/postgres/stable/V065__app_reward_hash_functions.sql new file mode 100644 index 0000000000..fda3f388c9 --- /dev/null +++ b/apps/common/src/main/resources/db/migration/canton-network/postgres/stable/V065__app_reward_hash_functions.sql @@ -0,0 +1,72 @@ +-- V065: plpgsql functions for Merkle tree hash computation over app reward batches. +-- These replicate the Daml CryptoHash module (Splice.Amulet.CryptoHash) +-- All hash functions return 64-char hex strings (text), matching Daml's Hash type. +-- Callers that store results in bytea columns (batch_hash, root_hash) must +-- convert with decode(result, 'hex'). + +-- ============================================================================ +-- Primitive hash functions matching Daml CryptoHash encoding +-- ============================================================================ + +-- Hash a text scalar: sha256(value) → 64-char hex string. +-- Matches: instance Hashable Text where hash = hashText . id +CREATE FUNCTION daml_crypto_hash_text(s text) RETURNS text + RETURNS NULL ON NULL INPUT + AS $$ SELECT encode(extensions.digest(s, 'sha256'), 'hex') $$ + LANGUAGE sql IMMUTABLE PARALLEL SAFE; + +-- Hash a list of already-hashed elements. +-- Matches: hashListInternal ts = sha256(intercalate "|" (show(length ts) :: ts)) +CREATE FUNCTION daml_crypto_hash_list(elems text[]) RETURNS text + RETURNS NULL ON NULL INPUT + AS $$ + SELECT encode(extensions.digest( + array_to_string( + ARRAY[cardinality(elems)::text] || elems, + '|' + ), + 'sha256' + ), 'hex') + $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; + +-- Hash a variant with a tag and field hashes. +-- Matches: hashVariant tag fields = sha256(intercalate "|" (tag :: show(length fields) :: map (.value) fields)) +CREATE FUNCTION daml_crypto_hash_variant(tag text, fields text[]) RETURNS text + RETURNS NULL ON NULL INPUT + AS $$ + SELECT encode(extensions.digest( + array_to_string( + ARRAY[tag, cardinality(fields)::text] || fields, + '|' + ), + 'sha256' + ), 'hex') + $$ LANGUAGE sql IMMUTABLE PARALLEL SAFE; + + +-- ============================================================================ +-- Domain-specific hash functions for reward accounting +-- ============================================================================ + +-- Hash a single MintingAllowance record. +-- Matches: hash MintingAllowance{provider, amount} = hashRecord [hash provider, hash amount] +CREATE FUNCTION hash_minting_allowance(provider text, amount text) RETURNS text + RETURNS NULL ON NULL INPUT + AS $$ SELECT daml_crypto_hash_list(ARRAY[daml_crypto_hash_text(provider), daml_crypto_hash_text(amount)]) $$ + LANGUAGE sql IMMUTABLE PARALLEL SAFE; + +-- Hash a BatchOfMintingAllowances variant. +-- Matches: hash (BatchOfMintingAllowances allowances) = hashVariant "BatchOfMintingAllowances" [hash allowances] +-- where hash allowances = hashList (map hash allowances) +CREATE FUNCTION hash_batch_of_minting_allowances(allowance_hashes text[]) RETURNS text + RETURNS NULL ON NULL INPUT + AS $$ SELECT daml_crypto_hash_variant('BatchOfMintingAllowances', ARRAY[daml_crypto_hash_list(allowance_hashes)]) $$ + LANGUAGE sql IMMUTABLE PARALLEL SAFE; + +-- Hash a BatchOfBatches variant. +-- Matches: hash (BatchOfBatches batchHashes) = hashVariant "BatchOfBatches" [hash batchHashes] +-- where hash batchHashes = hashList (map hash batchHashes) (identity on Hash) +CREATE FUNCTION hash_batch_of_batches(child_hashes text[]) RETURNS text + RETURNS NULL ON NULL INPUT + AS $$ SELECT daml_crypto_hash_variant('BatchOfBatches', ARRAY[daml_crypto_hash_list(child_hashes)]) $$ + LANGUAGE sql IMMUTABLE PARALLEL SAFE; diff --git a/daml/dars.lock b/daml/dars.lock index 0a78c3c8fc..88e234a941 100644 --- a/daml/dars.lock +++ b/daml/dars.lock @@ -35,8 +35,8 @@ splice-amulet-name-service 0.1.6 a208aab2c4a248ab2eff352bd382f8b3bbadc92464123db splice-amulet-name-service 0.1.7 ba7806d9b2d593eac74a050161c54ae1325d170bf175cb66a9c1e5e5ffb88c3d splice-amulet-name-service 0.1.8 efeb3f9b2b92e55fac4ec2d6164f95407a01477240c7465e576df4e310f54bd3 splice-amulet-name-service 0.1.9 f1b5915ad45ded616f43f83c735b7ee158b5eb58abe758a721e50eee19b3e531 -splice-amulet-name-service-test 0.1.21 b120f1061b3a4b278badcc27d2ab40bf9f5593a65b92fd1faa568ff02f6eba62 -splice-amulet-test 0.1.20 a9850c98ef59f0550ef7e036d11464bb8b7e97c4b7e88c8a390bbd27e946cca5 +splice-amulet-name-service-test 0.1.22 7be24690bd4b39a76d7245ddfae0c25a2f66c32099e17e856ddb92f5b944bea3 +splice-amulet-test 0.1.21 5657829c3084a8cf5a66c8da180d30aeb5977969e41723e3493ec82830407d17 splice-api-featured-app-v1 1.0.0 7804375fe5e4c6d5afe067bd314c42fe0b7d005a1300019c73154dd939da4dda splice-api-featured-app-v2 1.0.0 dd22e3e168a8c7fd0313171922dabf1f7a3b131bd9bfc9ff98e606f8c57707ea splice-api-token-allocation-instruction-v1 1.0.0 275064aacfe99cea72ee0c80563936129563776f67415ef9f13e4297eecbc520 @@ -72,7 +72,7 @@ splice-dso-governance 0.1.6 4e7653cfbf7ca249de4507aca9cd3b91060e5489042a522c589d splice-dso-governance 0.1.7 d406eba1132d464605f4dae3edf8cf5ecbbb34bd8edef0e047e7e526d328718c splice-dso-governance 0.1.8 1790a114f83d5f290261fae1e7e46fba75a861a3dd603c6b4ef6b67b49053948 splice-dso-governance 0.1.9 9ee83bfd872f91e659b8a8439c5b4eaf240bcf6f19698f884d7d7993ab48c401 -splice-dso-governance-test 0.1.27 46a2441bd370d21757a4f94fa44ba865f1cddf53ecec0e5a38bff84700977f00 +splice-dso-governance-test 0.1.28 33910e178389129fd916c577fbfd0a58ce86fe33db6a358e7dc988ee2ec014e8 splice-token-standard-test 1.0.11 b641f7509aff67cdfa82b66ebccfff072b2226b39e5bd998ac118570c926fc50 splice-token-test-dummy-holding 0.0.1 1cd171c6c42ab46dc9cf12d80c6111369e00cea5cdf054924b4f26ce94b1ef5b splice-token-test-dummy-holding 0.0.2 4f40fb033ef3db89623642c1b494e846097fa32af138b3864a63aa15937a323d @@ -139,7 +139,7 @@ splice-wallet-payments 0.1.6 6124379528eeb6fa17ecdab15577c29abb33d0c0d34dc5f2680 splice-wallet-payments 0.1.7 4e3e0d9cdadf80f4bf8f3cd3660d5287c084c9a29f23c901aabce597d72fd467 splice-wallet-payments 0.1.8 e48ea337ee3335c8bb3206a2501ce947ac1a7bdb1825cee8f28bad64f5a7bc4b splice-wallet-payments 0.1.9 7f4e081ad96f2ccded0c053b0cf5ddddae1139dfc3bb89cefcf77ea70f2cecb7 -splice-wallet-test 0.1.21 c751f85e42e928f0e300d561bda15be7bb42dd19681a52a4955d839f47f6b695 +splice-wallet-test 0.1.22 9d28b14cc32d128d0d6384eaae90c505f985a0c45d706caca483690b023efe60 splitwell 0.1.0 075c76de553ab88383a7c69de134afa82aacfdf8ea8fcfe8852c4b199c3b2669 splitwell 0.1.1 ccb1a0215053062202052e1a052f9214da3fdae5253a6d43e2e155ff4f57fe75 splitwell 0.1.10 d42676a366f7ca7a2409974dd3054aa4d83ab29baa3b2086ad021407b0a1a295 @@ -159,4 +159,4 @@ splitwell 0.1.6 872da0dd7986fd768930f85d6a7310a94a0ef924e7fbb7bb7a4e149f2b5feb74 splitwell 0.1.7 841d1c9c86b5c8f3a39059459ecd8febedf7703e18f117300bb0ebf4423db096 splitwell 0.1.8 63b8153a08ceb4bf40d807acc5712372c3eac548c266be4d5e92470b4f655515 splitwell 0.1.9 b6267905698d2798b9ef171e27d49fb88e052ec0ec0e0675a3a1b275c7d037d4 -splitwell-test 0.1.21 7cf052802bd7c9f3dcbe7f7af893e595310f7ec98fee05362208cb4808b3b61f \ No newline at end of file +splitwell-test 0.1.22 68088430da8cafaa5f8907aacdd4e257d838a6b58a3c1a29eb5555c8145483e4 \ No newline at end of file diff --git a/daml/splice-amulet-name-service-test/daml.yaml b/daml/splice-amulet-name-service-test/daml.yaml index d4dfda48ca..22ab8c22be 100644 --- a/daml/splice-amulet-name-service-test/daml.yaml +++ b/daml/splice-amulet-name-service-test/daml.yaml @@ -1,7 +1,7 @@ sdk-version: 3.3.0-snapshot.20250502.13767.0.v2fc6c7e2 name: splice-amulet-name-service-test source: daml -version: 0.1.21 +version: 0.1.22 dependencies: - daml-prim - daml-stdlib diff --git a/daml/splice-amulet-test/daml.yaml b/daml/splice-amulet-test/daml.yaml index c739b84549..a4b7014838 100644 --- a/daml/splice-amulet-test/daml.yaml +++ b/daml/splice-amulet-test/daml.yaml @@ -6,7 +6,7 @@ sdk-version: 3.3.0-snapshot.20250502.13767.0.v2fc6c7e2 name: splice-amulet-test source: daml -version: 0.1.20 +version: 0.1.21 dependencies: - daml-prim - daml-stdlib diff --git a/daml/splice-amulet-test/daml/Splice/Testing/CryptoHashProxy.daml b/daml/splice-amulet-test/daml/Splice/Testing/CryptoHashProxy.daml new file mode 100644 index 0000000000..0c13b83c02 --- /dev/null +++ b/daml/splice-amulet-test/daml/Splice/Testing/CryptoHashProxy.daml @@ -0,0 +1,93 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Splice.Testing.CryptoHashProxy where + +import DA.Text (intercalate, sha256) + +-- TODO(#4749): When Splice.Amulet.CryptoHash is merged, remove these +-- test-only copies and import from the real module instead. + +-- | Hash a text scalar: sha256(value). +-- Matches: instance Hashable Text where hash = hashText . id +hashText : Text -> Text +hashText = sha256 + +-- | Hash a list of already-hashed elements. +-- Matches: hashListInternal ts = sha256(intercalate "|" (show(length ts) :: ts)) +hashList : [Text] -> Text +hashList elems = + let parts = show (length elems) :: elems + in sha256 (intercalate "|" parts) + +-- | Hash a variant with a tag and field hashes. +-- Matches: hashVariant tag fields = sha256(intercalate "|" (tag :: show(length fields) :: fields)) +hashVariant : Text -> [Text] -> Text +hashVariant tag fieldHashes = + let parts = tag :: show (length fieldHashes) :: fieldHashes + in sha256 (intercalate "|" parts) + +-- | Hash a record as a list of field hashes. +hashRecord : [Text] -> Text +hashRecord = hashList + +-- | Hash a MintingAllowance{provider, amount}. +hashMintingAllowance : Text -> Text -> Text +hashMintingAllowance provider amount = + hashRecord [hashText provider, hashText amount] + +-- | Hash a BatchOfMintingAllowances variant. +hashBatchOfMintingAllowances : [Text] -> Text +hashBatchOfMintingAllowances allowanceHashes = + hashVariant "BatchOfMintingAllowances" [hashList allowanceHashes] + +-- | Hash a BatchOfBatches variant. +hashBatchOfBatches : [Text] -> Text +hashBatchOfBatches childHashes = + hashVariant "BatchOfBatches" [hashList childHashes] + +-- | Proxy template exposing hash functions as exercisable choices. +-- Allows Scala integration tests to call Daml hash functions via the +-- ledger API and compare results to SQL implementations. +template CryptoHashProxy with + owner : Party + where + signatory owner + + nonconsuming choice CryptoHashProxy_HashText : Text + with + input : Text + controller owner + do pure (hashText input) + + nonconsuming choice CryptoHashProxy_HashList : Text + with + elems : [Text] + controller owner + do pure (hashList elems) + + nonconsuming choice CryptoHashProxy_HashVariant : Text + with + tag : Text + fields : [Text] + controller owner + do pure (hashVariant tag fields) + + nonconsuming choice CryptoHashProxy_HashMintingAllowance : Text + with + provider : Text + amount : Text + controller owner + do pure (hashMintingAllowance provider amount) + + nonconsuming choice CryptoHashProxy_HashBatchOfMintingAllowances : Text + with + allowanceHashes : [Text] + controller owner + do pure (hashBatchOfMintingAllowances allowanceHashes) + + nonconsuming choice CryptoHashProxy_HashBatchOfBatches : Text + with + childHashes : [Text] + controller owner + do pure (hashBatchOfBatches childHashes) diff --git a/daml/splice-dso-governance-test/daml.yaml b/daml/splice-dso-governance-test/daml.yaml index a8bdf68f18..0e0acfcb9f 100644 --- a/daml/splice-dso-governance-test/daml.yaml +++ b/daml/splice-dso-governance-test/daml.yaml @@ -1,7 +1,7 @@ sdk-version: 3.3.0-snapshot.20250502.13767.0.v2fc6c7e2 name: splice-dso-governance-test source: daml -version: 0.1.27 +version: 0.1.28 dependencies: - daml-prim - daml-stdlib diff --git a/daml/splice-wallet-test/daml.yaml b/daml/splice-wallet-test/daml.yaml index 3ea53ca28d..490618978d 100644 --- a/daml/splice-wallet-test/daml.yaml +++ b/daml/splice-wallet-test/daml.yaml @@ -1,7 +1,7 @@ sdk-version: 3.3.0-snapshot.20250502.13767.0.v2fc6c7e2 name: splice-wallet-test source: daml -version: 0.1.21 +version: 0.1.22 dependencies: - daml-prim - daml-stdlib diff --git a/daml/splitwell-test/daml.yaml b/daml/splitwell-test/daml.yaml index 8473a63783..7ef619ce3c 100644 --- a/daml/splitwell-test/daml.yaml +++ b/daml/splitwell-test/daml.yaml @@ -1,7 +1,7 @@ sdk-version: 3.3.0-snapshot.20250502.13767.0.v2fc6c7e2 name: splitwell-test source: daml -version: 0.1.21 +version: 0.1.22 dependencies: - daml-prim - daml-stdlib diff --git a/test-full-class-names.log b/test-full-class-names.log index aaca015258..28e194e112 100644 --- a/test-full-class-names.log +++ b/test-full-class-names.log @@ -11,6 +11,7 @@ org.lfdecentralizedtrust.splice.integration.tests.BootstrapPackageConfigDarUploa org.lfdecentralizedtrust.splice.integration.tests.BootstrapTest org.lfdecentralizedtrust.splice.integration.tests.CombinedDumpDirectoryExportIntegrationTest org.lfdecentralizedtrust.splice.integration.tests.ConfigurationProvidedBftScanConnectionIntegrationTest +org.lfdecentralizedtrust.splice.integration.tests.CryptoHashEquivalenceIntegrationTest org.lfdecentralizedtrust.splice.integration.tests.DevelopmentFundCouponIntegrationTest org.lfdecentralizedtrust.splice.integration.tests.DirectoryPeriodicBackupIntegrationTest org.lfdecentralizedtrust.splice.integration.tests.DistributedDomainIntegrationTest