diff --git a/.claude/skills/build-fix/SKILL.md b/.claude/skills/build-fix/SKILL.md new file mode 100644 index 0000000000..0c1507056d --- /dev/null +++ b/.claude/skills/build-fix/SKILL.md @@ -0,0 +1,37 @@ +--- +name: build-fix +description: Build a cabal component with nix, parse GHC errors and warnings, fix them, and rebuild until clean. +disable-model-invocation: true +argument-hint: [nix-flake-target] +--- + +Build and iteratively fix GHC errors/warnings for the given nix flake target. + +If no argument is given, default to `'.#cardano-rpc:lib:cardano-rpc'`. + +Target: $ARGUMENTS + +## Procedure + +1. Run `nix build '' 2>&1` and capture the output. +2. Parse the output for GHC errors and warnings. +3. If there are errors, fix them one category at a time: + - **Missing imports**: Look up which module exports the symbol. Remember that RIO does NOT re-export everything from Prelude/Data.List (e.g. `sortBy`, `on` need explicit imports). + - **Type mismatches**: Analyze carefully. In cardano-rpc, remember that `Proto msg` is a grapesy wrapper — internal functions use plain proto-lens types, `getProto`/`fmap getProto` at handler boundaries only. + - **Not in scope**: Check if it's a missing import or a typo. + - **Redundant constraints**: Remove them. + - **Redundant imports**: Remove them. + - **Deprecated functions**: Replace with the recommended alternative (e.g. `valueToList` -> `toList` from `GHC.IsList`). +4. After fixing, rebuild. +5. Repeat until the build succeeds with no errors. +6. If there are warnings remaining, fix them too: + - Redundant imports/constraints: remove + - hlint-style suggestions: apply (e.g. lambda to infix) + - Deprecated usage: replace +7. Rebuild one final time to confirm clean output. + +## Important rules +- NEVER manually edit files under `gen/` — those are generated by proto-lens. +- If proto generated code needs updating, use `/proto-gen` instead. +- RIO's `^.` works with proto-lens lenses. Do NOT add `lens-family` as a dependency. +- Verify fixes carefully before rebuilding to minimize nix build round-trips (each takes minutes). diff --git a/.claude/skills/proto-gen/SKILL.md b/.claude/skills/proto-gen/SKILL.md new file mode 100644 index 0000000000..2d549a0001 --- /dev/null +++ b/.claude/skills/proto-gen/SKILL.md @@ -0,0 +1,23 @@ +--- +name: proto-gen +description: Regenerate proto-lens Haskell code from .proto files using buf in the nix dev shell. +disable-model-invocation: true +argument-hint: [package-dir] +--- + +Regenerate proto-lens code from .proto files. + +If no argument is given, default to `cardano-rpc`. + +Package directory: $ARGUMENTS + +## Procedure + +1. Run: `nix develop --command bash -c "cd && buf generate proto"` +2. Verify the command succeeded. +3. Show a summary of which files were regenerated (check git status for changed files under `/gen/`). + +## Important rules +- NEVER manually edit files under `gen/` — they are overwritten by this command. +- If buf or proto-lens-protoc are not found, it means you're not in the nix dev shell — always use `nix develop --command`. +- After regeneration, you may need to run `/build-fix` to ensure everything compiles. diff --git a/.claude/skills/rio-check/SKILL.md b/.claude/skills/rio-check/SKILL.md new file mode 100644 index 0000000000..13b89a2530 --- /dev/null +++ b/.claude/skills/rio-check/SKILL.md @@ -0,0 +1,30 @@ +--- +name: rio-check +description: Check if a Haskell function or type is re-exported by the RIO module. +disable-model-invocation: true +argument-hint: [symbol-name] +--- + +Check whether the symbol `$ARGUMENTS` is re-exported by RIO. + +## Procedure + +1. Find the RIO package source in the nix store by searching for the RIO module file: + ``` + find /nix/store -path '*/RIO.hs' -name 'RIO.hs' 2>/dev/null | head -5 + ``` + Or search the project's dependency tree: + ``` + grep -r 'module RIO' $(nix build '.#cardano-rpc:lib:cardano-rpc' --print-out-paths 2>/dev/null)/lib/ 2>/dev/null + ``` +2. Search for the symbol in RIO's module exports and re-exports. +3. Report: + - Whether the symbol is available from RIO + - If NOT available, which module to import it from (e.g. `Data.List`, `Data.Map`, etc.) + - Whether RIO hides it (some symbols are explicitly hidden, like `toList`) + +## Known RIO gaps (common gotchas) +- `sortBy` — NOT in RIO, import from `Data.List` +- `on` — NOT in RIO, import from `Data.Function` +- `toList` — RIO re-exports from GHC.Exts but some modules hide it; use `GHC.IsList` or import explicitly +- `sortOn`, `sort` — available in RIO diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..b4823c4da8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,21 @@ +# Claude Code notes + +## Rules +- Never manually edit generated code (e.g. proto-lens output in `gen/`). Use nix dev shell to run code generation tools (e.g. `nix develop --command bash -c "cd cardano-rpc && buf generate proto"`) +- Never modify the nix store + +## cardano-rpc patterns +- `Proto msg` is a grapesy newtype wrapper. Internal functions should use plain proto-lens types, not `Proto`-wrapped. Use `getProto`/`fmap getProto` only at the RPC handler boundary. +- RIO hides many Prelude functions. `sortBy` is NOT re-exported by RIO -- import from `Data.List`. Check RIO re-exports before assuming standard functions are in scope. +- RIO's `^.` works with proto-lens van Laarhoven lenses. No need for `lens-family` dependency. +- Use `toList` (from `GHC.IsList`) instead of deprecated `valueToList` for `Value`. + +## Mistakes and wrong assumptions (lessons learned) +- Assumed generated code could be patched by hand -- WRONG. Always use the project's code generation pipeline. +- Assumed proto-lens types would be used wrapped in `Proto` everywhere -- WRONG. `Proto` is only at the gRPC handler boundary. Internal logic uses raw proto-lens types. +- Assumed RIO re-exports all of `Data.List` -- WRONG. `sortBy`, `on`, and others need explicit imports. +- Assumed I needed `lens-family` for proto-lens field access -- WRONG. RIO's `^.` (from `microlens`) is compatible with proto-lens van Laarhoven lenses. +- Used deprecated `valueToList` instead of checking for the current API (`toList` via `GHC.IsList`). +- Left redundant `IsEra` constraint on `matchesTxOutputPattern` -- should check if constraints are actually needed before adding them. +- Wrote lambdas where infix notation was cleaner (`\sub -> f sub x` vs `` `f` x ``). hlint caught this. +- Minimize nix build round-trips: verify types, imports, and constraints carefully before building. diff --git a/cardano-rpc/cardano-rpc.cabal b/cardano-rpc/cardano-rpc.cabal index 620a58855c..306a8cc45c 100644 --- a/cardano-rpc/cardano-rpc.cabal +++ b/cardano-rpc/cardano-rpc.cabal @@ -58,6 +58,7 @@ library Cardano.Rpc.Server.Internal.Monad Cardano.Rpc.Server.Internal.Node Cardano.Rpc.Server.Internal.Tracing + Cardano.Rpc.Server.Internal.UtxoRpc.Predicate Cardano.Rpc.Server.Internal.UtxoRpc.Query Cardano.Rpc.Server.Internal.UtxoRpc.Submit Cardano.Rpc.Server.Internal.UtxoRpc.Type @@ -119,15 +120,18 @@ test-suite cardano-rpc-test type: exitcode-stdio-1.0 build-depends: base, + bytestring, cardano-api, cardano-api:gen, cardano-ledger-api, cardano-ledger-conway, cardano-ledger-core, cardano-rpc, + cardano-rpc:gen, containers, hedgehog, hedgehog-extras, + proto-lens, rio, tasty, tasty-hedgehog, @@ -139,6 +143,7 @@ test-suite cardano-rpc-test build-tool-depends: tasty-discover:tasty-discover other-modules: + Test.Cardano.Rpc.Predicate Test.Cardano.Rpc.ProtocolParameters Test.Cardano.Rpc.TxOutput Test.Cardano.Rpc.Type diff --git a/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano.hs b/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano.hs index 3cb3e14087..105e4e54de 100644 --- a/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano.hs +++ b/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano.hs @@ -110,12 +110,15 @@ import qualified Data.ProtoLens.Runtime.Text.Read as Text.Read {- | Fields : * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.exactAddress' @:: Lens' AddressPattern Data.ByteString.ByteString@ + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.maybe'exactAddress' @:: Lens' AddressPattern (Prelude.Maybe Data.ByteString.ByteString)@ * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.paymentPart' @:: Lens' AddressPattern Data.ByteString.ByteString@ - * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.delegationPart' @:: Lens' AddressPattern Data.ByteString.ByteString@ -} + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.maybe'paymentPart' @:: Lens' AddressPattern (Prelude.Maybe Data.ByteString.ByteString)@ + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.delegationPart' @:: Lens' AddressPattern Data.ByteString.ByteString@ + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.maybe'delegationPart' @:: Lens' AddressPattern (Prelude.Maybe Data.ByteString.ByteString)@ -} data AddressPattern - = AddressPattern'_constructor {_AddressPattern'exactAddress :: !Data.ByteString.ByteString, - _AddressPattern'paymentPart :: !Data.ByteString.ByteString, - _AddressPattern'delegationPart :: !Data.ByteString.ByteString, + = AddressPattern'_constructor {_AddressPattern'exactAddress :: !(Prelude.Maybe Data.ByteString.ByteString), + _AddressPattern'paymentPart :: !(Prelude.Maybe Data.ByteString.ByteString), + _AddressPattern'delegationPart :: !(Prelude.Maybe Data.ByteString.ByteString), _AddressPattern'_unknownFields :: !Data.ProtoLens.FieldSet} deriving stock (Prelude.Eq, Prelude.Ord) instance Prelude.Show AddressPattern where @@ -125,6 +128,13 @@ instance Prelude.Show AddressPattern where (Prelude.showString (Data.ProtoLens.showMessageShort __x) (Prelude.showChar '}' __s)) instance Data.ProtoLens.Field.HasField AddressPattern "exactAddress" Data.ByteString.ByteString where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _AddressPattern'exactAddress + (\ x__ y__ -> x__ {_AddressPattern'exactAddress = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField AddressPattern "maybe'exactAddress" (Prelude.Maybe Data.ByteString.ByteString) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -132,6 +142,13 @@ instance Data.ProtoLens.Field.HasField AddressPattern "exactAddress" Data.ByteSt (\ x__ y__ -> x__ {_AddressPattern'exactAddress = y__})) Prelude.id instance Data.ProtoLens.Field.HasField AddressPattern "paymentPart" Data.ByteString.ByteString where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _AddressPattern'paymentPart + (\ x__ y__ -> x__ {_AddressPattern'paymentPart = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField AddressPattern "maybe'paymentPart" (Prelude.Maybe Data.ByteString.ByteString) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -139,6 +156,13 @@ instance Data.ProtoLens.Field.HasField AddressPattern "paymentPart" Data.ByteStr (\ x__ y__ -> x__ {_AddressPattern'paymentPart = y__})) Prelude.id instance Data.ProtoLens.Field.HasField AddressPattern "delegationPart" Data.ByteString.ByteString where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _AddressPattern'delegationPart + (\ x__ y__ -> x__ {_AddressPattern'delegationPart = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField AddressPattern "maybe'delegationPart" (Prelude.Maybe Data.ByteString.ByteString) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -150,10 +174,13 @@ instance Data.ProtoLens.Message AddressPattern where = Data.Text.pack "utxorpc.v1beta.cardano.AddressPattern" packedMessageDescriptor _ = "\n\ - \\SOAddressPattern\DC2#\n\ - \\rexact_address\CAN\SOH \SOH(\fR\fexactAddress\DC2!\n\ - \\fpayment_part\CAN\STX \SOH(\fR\vpaymentPart\DC2'\n\ - \\SIdelegation_part\CAN\ETX \SOH(\fR\SOdelegationPart" + \\SOAddressPattern\DC2(\n\ + \\rexact_address\CAN\SOH \SOH(\fH\NULR\fexactAddress\136\SOH\SOH\DC2&\n\ + \\fpayment_part\CAN\STX \SOH(\fH\SOHR\vpaymentPart\136\SOH\SOH\DC2,\n\ + \\SIdelegation_part\CAN\ETX \SOH(\fH\STXR\SOdelegationPart\136\SOH\SOHB\DLE\n\ + \\SO_exact_addressB\SI\n\ + \\r_payment_partB\DC2\n\ + \\DLE_delegation_part" packedFileDescriptor _ = packedFileDescriptor fieldsByTag = let @@ -162,27 +189,24 @@ instance Data.ProtoLens.Message AddressPattern where "exact_address" (Data.ProtoLens.ScalarField Data.ProtoLens.BytesField :: Data.ProtoLens.FieldTypeDescriptor Data.ByteString.ByteString) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"exactAddress")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'exactAddress")) :: Data.ProtoLens.FieldDescriptor AddressPattern paymentPart__field_descriptor = Data.ProtoLens.FieldDescriptor "payment_part" (Data.ProtoLens.ScalarField Data.ProtoLens.BytesField :: Data.ProtoLens.FieldTypeDescriptor Data.ByteString.ByteString) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"paymentPart")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'paymentPart")) :: Data.ProtoLens.FieldDescriptor AddressPattern delegationPart__field_descriptor = Data.ProtoLens.FieldDescriptor "delegation_part" (Data.ProtoLens.ScalarField Data.ProtoLens.BytesField :: Data.ProtoLens.FieldTypeDescriptor Data.ByteString.ByteString) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"delegationPart")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'delegationPart")) :: Data.ProtoLens.FieldDescriptor AddressPattern in Data.Map.fromList @@ -195,9 +219,9 @@ instance Data.ProtoLens.Message AddressPattern where (\ x__ y__ -> x__ {_AddressPattern'_unknownFields = y__}) defMessage = AddressPattern'_constructor - {_AddressPattern'exactAddress = Data.ProtoLens.fieldDefault, - _AddressPattern'paymentPart = Data.ProtoLens.fieldDefault, - _AddressPattern'delegationPart = Data.ProtoLens.fieldDefault, + {_AddressPattern'exactAddress = Prelude.Nothing, + _AddressPattern'paymentPart = Prelude.Nothing, + _AddressPattern'delegationPart = Prelude.Nothing, _AddressPattern'_unknownFields = []} parseMessage = let @@ -260,54 +284,50 @@ instance Data.ProtoLens.Message AddressPattern where buildMessage = \ _x -> (Data.Monoid.<>) - (let - _v - = Lens.Family2.view (Data.ProtoLens.Field.field @"exactAddress") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 10) - ((\ bs - -> (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt - (Prelude.fromIntegral (Data.ByteString.length bs))) - (Data.ProtoLens.Encoding.Bytes.putBytes bs)) - _v)) + (case + Lens.Family2.view + (Data.ProtoLens.Field.field @"maybe'exactAddress") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 10) + ((\ bs + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt + (Prelude.fromIntegral (Data.ByteString.length bs))) + (Data.ProtoLens.Encoding.Bytes.putBytes bs)) + _v)) ((Data.Monoid.<>) - (let - _v - = Lens.Family2.view (Data.ProtoLens.Field.field @"paymentPart") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 18) - ((\ bs - -> (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt - (Prelude.fromIntegral (Data.ByteString.length bs))) - (Data.ProtoLens.Encoding.Bytes.putBytes bs)) - _v)) + (case + Lens.Family2.view + (Data.ProtoLens.Field.field @"maybe'paymentPart") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 18) + ((\ bs + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt + (Prelude.fromIntegral (Data.ByteString.length bs))) + (Data.ProtoLens.Encoding.Bytes.putBytes bs)) + _v)) ((Data.Monoid.<>) - (let - _v - = Lens.Family2.view - (Data.ProtoLens.Field.field @"delegationPart") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 26) - ((\ bs - -> (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt - (Prelude.fromIntegral (Data.ByteString.length bs))) - (Data.ProtoLens.Encoding.Bytes.putBytes bs)) - _v)) + (case + Lens.Family2.view + (Data.ProtoLens.Field.field @"maybe'delegationPart") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 26) + ((\ bs + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt + (Prelude.fromIntegral (Data.ByteString.length bs))) + (Data.ProtoLens.Encoding.Bytes.putBytes bs)) + _v)) (Data.ProtoLens.Encoding.Wire.buildFieldSet (Lens.Family2.view Data.ProtoLens.unknownFields _x)))) instance Control.DeepSeq.NFData AddressPattern where @@ -636,10 +656,12 @@ instance Control.DeepSeq.NFData Asset where {- | Fields : * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.policyId' @:: Lens' AssetPattern Data.ByteString.ByteString@ - * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.assetName' @:: Lens' AssetPattern Data.ByteString.ByteString@ -} + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.maybe'policyId' @:: Lens' AssetPattern (Prelude.Maybe Data.ByteString.ByteString)@ + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.assetName' @:: Lens' AssetPattern Data.ByteString.ByteString@ + * 'Proto.Utxorpc.V1beta.Cardano.Cardano_Fields.maybe'assetName' @:: Lens' AssetPattern (Prelude.Maybe Data.ByteString.ByteString)@ -} data AssetPattern - = AssetPattern'_constructor {_AssetPattern'policyId :: !Data.ByteString.ByteString, - _AssetPattern'assetName :: !Data.ByteString.ByteString, + = AssetPattern'_constructor {_AssetPattern'policyId :: !(Prelude.Maybe Data.ByteString.ByteString), + _AssetPattern'assetName :: !(Prelude.Maybe Data.ByteString.ByteString), _AssetPattern'_unknownFields :: !Data.ProtoLens.FieldSet} deriving stock (Prelude.Eq, Prelude.Ord) instance Prelude.Show AssetPattern where @@ -649,6 +671,13 @@ instance Prelude.Show AssetPattern where (Prelude.showString (Data.ProtoLens.showMessageShort __x) (Prelude.showChar '}' __s)) instance Data.ProtoLens.Field.HasField AssetPattern "policyId" Data.ByteString.ByteString where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _AssetPattern'policyId + (\ x__ y__ -> x__ {_AssetPattern'policyId = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField AssetPattern "maybe'policyId" (Prelude.Maybe Data.ByteString.ByteString) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -656,6 +685,13 @@ instance Data.ProtoLens.Field.HasField AssetPattern "policyId" Data.ByteString.B (\ x__ y__ -> x__ {_AssetPattern'policyId = y__})) Prelude.id instance Data.ProtoLens.Field.HasField AssetPattern "assetName" Data.ByteString.ByteString where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _AssetPattern'assetName + (\ x__ y__ -> x__ {_AssetPattern'assetName = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField AssetPattern "maybe'assetName" (Prelude.Maybe Data.ByteString.ByteString) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -667,10 +703,13 @@ instance Data.ProtoLens.Message AssetPattern where = Data.Text.pack "utxorpc.v1beta.cardano.AssetPattern" packedMessageDescriptor _ = "\n\ - \\fAssetPattern\DC2\ESC\n\ - \\tpolicy_id\CAN\SOH \SOH(\fR\bpolicyId\DC2\GS\n\ + \\fAssetPattern\DC2 \n\ + \\tpolicy_id\CAN\SOH \SOH(\fH\NULR\bpolicyId\136\SOH\SOH\DC2\"\n\ + \\n\ + \asset_name\CAN\STX \SOH(\fH\SOHR\tassetName\136\SOH\SOHB\f\n\ \\n\ - \asset_name\CAN\STX \SOH(\fR\tassetName" + \_policy_idB\r\n\ + \\v_asset_name" packedFileDescriptor _ = packedFileDescriptor fieldsByTag = let @@ -679,18 +718,16 @@ instance Data.ProtoLens.Message AssetPattern where "policy_id" (Data.ProtoLens.ScalarField Data.ProtoLens.BytesField :: Data.ProtoLens.FieldTypeDescriptor Data.ByteString.ByteString) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"policyId")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'policyId")) :: Data.ProtoLens.FieldDescriptor AssetPattern assetName__field_descriptor = Data.ProtoLens.FieldDescriptor "asset_name" (Data.ProtoLens.ScalarField Data.ProtoLens.BytesField :: Data.ProtoLens.FieldTypeDescriptor Data.ByteString.ByteString) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"assetName")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'assetName")) :: Data.ProtoLens.FieldDescriptor AssetPattern in Data.Map.fromList @@ -702,8 +739,8 @@ instance Data.ProtoLens.Message AssetPattern where (\ x__ y__ -> x__ {_AssetPattern'_unknownFields = y__}) defMessage = AssetPattern'_constructor - {_AssetPattern'policyId = Data.ProtoLens.fieldDefault, - _AssetPattern'assetName = Data.ProtoLens.fieldDefault, + {_AssetPattern'policyId = Prelude.Nothing, + _AssetPattern'assetName = Prelude.Nothing, _AssetPattern'_unknownFields = []} parseMessage = let @@ -755,35 +792,34 @@ instance Data.ProtoLens.Message AssetPattern where buildMessage = \ _x -> (Data.Monoid.<>) - (let - _v = Lens.Family2.view (Data.ProtoLens.Field.field @"policyId") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 10) - ((\ bs - -> (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt - (Prelude.fromIntegral (Data.ByteString.length bs))) - (Data.ProtoLens.Encoding.Bytes.putBytes bs)) - _v)) + (case + Lens.Family2.view (Data.ProtoLens.Field.field @"maybe'policyId") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 10) + ((\ bs + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt + (Prelude.fromIntegral (Data.ByteString.length bs))) + (Data.ProtoLens.Encoding.Bytes.putBytes bs)) + _v)) ((Data.Monoid.<>) - (let - _v = Lens.Family2.view (Data.ProtoLens.Field.field @"assetName") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 18) - ((\ bs - -> (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt - (Prelude.fromIntegral (Data.ByteString.length bs))) - (Data.ProtoLens.Encoding.Bytes.putBytes bs)) - _v)) + (case + Lens.Family2.view + (Data.ProtoLens.Field.field @"maybe'assetName") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 18) + ((\ bs + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt + (Prelude.fromIntegral (Data.ByteString.length bs))) + (Data.ProtoLens.Encoding.Bytes.putBytes bs)) + _v)) (Data.ProtoLens.Encoding.Wire.buildFieldSet (Lens.Family2.view Data.ProtoLens.unknownFields _x))) instance Control.DeepSeq.NFData AssetPattern where @@ -27974,9 +28010,12 @@ instance Data.ProtoLens.Message TxOutputPattern where = Data.Text.pack "utxorpc.v1beta.cardano.TxOutputPattern" packedMessageDescriptor _ = "\n\ - \\SITxOutputPattern\DC2@\n\ - \\aaddress\CAN\SOH \SOH(\v2&.utxorpc.v1beta.cardano.AddressPatternR\aaddress\DC2:\n\ - \\ENQasset\CAN\STX \SOH(\v2$.utxorpc.v1beta.cardano.AssetPatternR\ENQasset" + \\SITxOutputPattern\DC2E\n\ + \\aaddress\CAN\SOH \SOH(\v2&.utxorpc.v1beta.cardano.AddressPatternH\NULR\aaddress\136\SOH\SOH\DC2?\n\ + \\ENQasset\CAN\STX \SOH(\v2$.utxorpc.v1beta.cardano.AssetPatternH\SOHR\ENQasset\136\SOH\SOHB\n\ + \\n\ + \\b_addressB\b\n\ + \\ACK_asset" packedFileDescriptor _ = packedFileDescriptor fieldsByTag = let @@ -31565,15 +31604,21 @@ packedFileDescriptor \\EOTcoin\CAN\STX \SOH(\v2\RS.utxorpc.v1beta.cardano.BigIntR\EOTcoin\"\154\SOH\n\ \\SOUpdateDRepCert\DC2P\n\ \\SIdrep_credential\CAN\SOH \SOH(\v2'.utxorpc.v1beta.cardano.StakeCredentialR\SOdrepCredential\DC26\n\ - \\ACKanchor\CAN\STX \SOH(\v2\RS.utxorpc.v1beta.cardano.AnchorR\ACKanchor\"\129\SOH\n\ - \\SOAddressPattern\DC2#\n\ - \\rexact_address\CAN\SOH \SOH(\fR\fexactAddress\DC2!\n\ - \\fpayment_part\CAN\STX \SOH(\fR\vpaymentPart\DC2'\n\ - \\SIdelegation_part\CAN\ETX \SOH(\fR\SOdelegationPart\"J\n\ - \\fAssetPattern\DC2\ESC\n\ - \\tpolicy_id\CAN\SOH \SOH(\fR\bpolicyId\DC2\GS\n\ - \\n\ - \asset_name\CAN\STX \SOH(\fR\tassetName\"\244\EOT\n\ + \\ACKanchor\CAN\STX \SOH(\v2\RS.utxorpc.v1beta.cardano.AnchorR\ACKanchor\"\199\SOH\n\ + \\SOAddressPattern\DC2(\n\ + \\rexact_address\CAN\SOH \SOH(\fH\NULR\fexactAddress\136\SOH\SOH\DC2&\n\ + \\fpayment_part\CAN\STX \SOH(\fH\SOHR\vpaymentPart\136\SOH\SOH\DC2,\n\ + \\SIdelegation_part\CAN\ETX \SOH(\fH\STXR\SOdelegationPart\136\SOH\SOHB\DLE\n\ + \\SO_exact_addressB\SI\n\ + \\r_payment_partB\DC2\n\ + \\DLE_delegation_part\"q\n\ + \\fAssetPattern\DC2 \n\ + \\tpolicy_id\CAN\SOH \SOH(\fH\NULR\bpolicyId\136\SOH\SOH\DC2\"\n\ + \\n\ + \asset_name\CAN\STX \SOH(\fH\SOHR\tassetName\136\SOH\SOHB\f\n\ + \\n\ + \_policy_idB\r\n\ + \\v_asset_name\"\244\EOT\n\ \\DC2CertificatePattern\DC2X\n\ \\DC2stake_registration\CAN\SOH \SOH(\v2'.utxorpc.v1beta.cardano.StakeCredentialH\NULR\DC1stakeRegistration\DC2\\\n\ \\DC4stake_deregistration\CAN\STX \SOH(\v2'.utxorpc.v1beta.cardano.StakeCredentialH\NULR\DC3stakeDeregistration\DC2[\n\ @@ -31592,10 +31637,13 @@ packedFileDescriptor \\fpool_keyhash\CAN\STX \SOH(\fR\vpoolKeyhash\"P\n\ \\NAKPoolRetirementPattern\DC2!\n\ \\fpool_keyhash\CAN\SOH \SOH(\fR\vpoolKeyhash\DC2\DC4\n\ - \\ENQepoch\CAN\STX \SOH(\EOTR\ENQepoch\"\143\SOH\n\ - \\SITxOutputPattern\DC2@\n\ - \\aaddress\CAN\SOH \SOH(\v2&.utxorpc.v1beta.cardano.AddressPatternR\aaddress\DC2:\n\ - \\ENQasset\CAN\STX \SOH(\v2$.utxorpc.v1beta.cardano.AssetPatternR\ENQasset\"\193\ETX\n\ + \\ENQepoch\CAN\STX \SOH(\EOTR\ENQepoch\"\175\SOH\n\ + \\SITxOutputPattern\DC2E\n\ + \\aaddress\CAN\SOH \SOH(\v2&.utxorpc.v1beta.cardano.AddressPatternH\NULR\aaddress\136\SOH\SOH\DC2?\n\ + \\ENQasset\CAN\STX \SOH(\v2$.utxorpc.v1beta.cardano.AssetPatternH\SOHR\ENQasset\136\SOH\SOHB\n\ + \\n\ + \\b_addressB\b\n\ + \\ACK_asset\"\193\ETX\n\ \\tTxPattern\DC2C\n\ \\bconsumes\CAN\SOH \SOH(\v2'.utxorpc.v1beta.cardano.TxOutputPatternR\bconsumes\DC2C\n\ \\bproduces\CAN\STX \SOH(\v2'.utxorpc.v1beta.cardano.TxOutputPatternR\bproduces\DC2G\n\ @@ -31843,7 +31891,7 @@ packedFileDescriptor \\SYNMIR_SOURCE_UNSPECIFIED\DLE\NUL\DC2\ETB\n\ \\DC3MIR_SOURCE_RESERVES\DLE\SOH\DC2\ETB\n\ \\DC3MIR_SOURCE_TREASURY\DLE\STXB\164\SOH\n\ - \\SUBcom.utxorpc.v1beta.cardanoB\fCardanoProtoP\SOH\162\STX\ETXUVC\170\STX\SYNUtxorpc.V1beta.Cardano\202\STX\SYNUtxorpc\\V1beta\\Cardano\226\STX\"Utxorpc\\V1beta\\Cardano\\GPBMetadata\234\STX\CANUtxorpc::V1beta::CardanoJ\171\173\STX\n\ + \\SUBcom.utxorpc.v1beta.cardanoB\fCardanoProtoP\SOH\162\STX\ETXUVC\170\STX\SYNUtxorpc.V1beta.Cardano\202\STX\SYNUtxorpc\\V1beta\\Cardano\226\STX\"Utxorpc\\V1beta\\Cardano\\GPBMetadata\234\STX\CANUtxorpc::V1beta::CardanoJ\148\174\STX\n\ \\a\DC2\ENQ\NUL\NUL\185\ACK\SOH\n\ \\b\n\ \\SOH\f\DC2\ETX\NUL\NUL\DC2\n\ @@ -34394,55 +34442,70 @@ packedFileDescriptor \\v\n\ \\ETX\EOTF\SOH\DC2\EOT\133\EOT\b\SYN\n\ \B\n\ - \\EOT\EOTF\STX\NUL\DC2\EOT\134\EOT\STX\SUB\"4 The address should match this exact address value.\n\ + \\EOT\EOTF\STX\NUL\DC2\EOT\134\EOT\STX#\"4 The address should match this exact address value.\n\ \\n\ \\r\n\ - \\ENQ\EOTF\STX\NUL\ENQ\DC2\EOT\134\EOT\STX\a\n\ + \\ENQ\EOTF\STX\NUL\EOT\DC2\EOT\134\EOT\STX\n\ + \\n\ + \\r\n\ + \\ENQ\EOTF\STX\NUL\ENQ\DC2\EOT\134\EOT\v\DLE\n\ \\r\n\ - \\ENQ\EOTF\STX\NUL\SOH\DC2\EOT\134\EOT\b\NAK\n\ + \\ENQ\EOTF\STX\NUL\SOH\DC2\EOT\134\EOT\DC1\RS\n\ \\r\n\ - \\ENQ\EOTF\STX\NUL\ETX\DC2\EOT\134\EOT\CAN\EM\n\ + \\ENQ\EOTF\STX\NUL\ETX\DC2\EOT\134\EOT!\"\n\ \H\n\ - \\EOT\EOTF\STX\SOH\DC2\EOT\135\EOT\STX\EM\": The payment part of the address should match this value.\n\ + \\EOT\EOTF\STX\SOH\DC2\EOT\135\EOT\STX\"\": The payment part of the address should match this value.\n\ \\n\ \\r\n\ - \\ENQ\EOTF\STX\SOH\ENQ\DC2\EOT\135\EOT\STX\a\n\ + \\ENQ\EOTF\STX\SOH\EOT\DC2\EOT\135\EOT\STX\n\ + \\n\ \\r\n\ - \\ENQ\EOTF\STX\SOH\SOH\DC2\EOT\135\EOT\b\DC4\n\ + \\ENQ\EOTF\STX\SOH\ENQ\DC2\EOT\135\EOT\v\DLE\n\ \\r\n\ - \\ENQ\EOTF\STX\SOH\ETX\DC2\EOT\135\EOT\ETB\CAN\n\ + \\ENQ\EOTF\STX\SOH\SOH\DC2\EOT\135\EOT\DC1\GS\n\ + \\r\n\ + \\ENQ\EOTF\STX\SOH\ETX\DC2\EOT\135\EOT !\n\ \K\n\ - \\EOT\EOTF\STX\STX\DC2\EOT\136\EOT\STX\FS\"= The delegation part of the address should match this value.\n\ + \\EOT\EOTF\STX\STX\DC2\EOT\136\EOT\STX%\"= The delegation part of the address should match this value.\n\ + \\n\ + \\r\n\ + \\ENQ\EOTF\STX\STX\EOT\DC2\EOT\136\EOT\STX\n\ \\n\ \\r\n\ - \\ENQ\EOTF\STX\STX\ENQ\DC2\EOT\136\EOT\STX\a\n\ + \\ENQ\EOTF\STX\STX\ENQ\DC2\EOT\136\EOT\v\DLE\n\ \\r\n\ - \\ENQ\EOTF\STX\STX\SOH\DC2\EOT\136\EOT\b\ETB\n\ + \\ENQ\EOTF\STX\STX\SOH\DC2\EOT\136\EOT\DC1 \n\ \\r\n\ - \\ENQ\EOTF\STX\STX\ETX\DC2\EOT\136\EOT\SUB\ESC\n\ + \\ENQ\EOTF\STX\STX\ETX\DC2\EOT\136\EOT#$\n\ \[\n\ \\STX\EOTG\DC2\ACK\140\EOT\NUL\143\EOT\SOH\SUBM Pattern of a native asset that can be used to evaluate matching predicates.\n\ \\n\ \\v\n\ \\ETX\EOTG\SOH\DC2\EOT\140\EOT\b\DC4\n\ \9\n\ - \\EOT\EOTG\STX\NUL\DC2\EOT\141\EOT\STX\SYN\"+ The asset should belong to this policy id\n\ + \\EOT\EOTG\STX\NUL\DC2\EOT\141\EOT\STX\US\"+ The asset should belong to this policy id\n\ \\n\ \\r\n\ - \\ENQ\EOTG\STX\NUL\ENQ\DC2\EOT\141\EOT\STX\a\n\ + \\ENQ\EOTG\STX\NUL\EOT\DC2\EOT\141\EOT\STX\n\ + \\n\ + \\r\n\ + \\ENQ\EOTG\STX\NUL\ENQ\DC2\EOT\141\EOT\v\DLE\n\ \\r\n\ - \\ENQ\EOTG\STX\NUL\SOH\DC2\EOT\141\EOT\b\DC1\n\ + \\ENQ\EOTG\STX\NUL\SOH\DC2\EOT\141\EOT\DC1\SUB\n\ \\r\n\ - \\ENQ\EOTG\STX\NUL\ETX\DC2\EOT\141\EOT\DC4\NAK\n\ + \\ENQ\EOTG\STX\NUL\ETX\DC2\EOT\141\EOT\GS\RS\n\ \2\n\ - \\EOT\EOTG\STX\SOH\DC2\EOT\142\EOT\STX\ETB\"$ The asset should present this name\n\ + \\EOT\EOTG\STX\SOH\DC2\EOT\142\EOT\STX \"$ The asset should present this name\n\ \\n\ \\r\n\ - \\ENQ\EOTG\STX\SOH\ENQ\DC2\EOT\142\EOT\STX\a\n\ + \\ENQ\EOTG\STX\SOH\EOT\DC2\EOT\142\EOT\STX\n\ + \\n\ \\r\n\ - \\ENQ\EOTG\STX\SOH\SOH\DC2\EOT\142\EOT\b\DC2\n\ + \\ENQ\EOTG\STX\SOH\ENQ\DC2\EOT\142\EOT\v\DLE\n\ \\r\n\ - \\ENQ\EOTG\STX\SOH\ETX\DC2\EOT\142\EOT\NAK\SYN\n\ + \\ENQ\EOTG\STX\SOH\SOH\DC2\EOT\142\EOT\DC1\ESC\n\ + \\r\n\ + \\ENQ\EOTG\STX\SOH\ETX\DC2\EOT\142\EOT\RS\US\n\ \Z\n\ \\STX\EOTH\DC2\ACK\146\EOT\NUL\157\EOT\SOH\SUBL Pattern of a certificate that can be used to evaluate matching predicates.\n\ \\n\ @@ -34602,23 +34665,29 @@ packedFileDescriptor \\v\n\ \\ETX\EOTL\SOH\DC2\EOT\178\EOT\b\ETB\n\ \K\n\ - \\EOT\EOTL\STX\NUL\DC2\EOT\179\EOT\STX\GS\"= Match any address in the output that exhibits this pattern.\n\ + \\EOT\EOTL\STX\NUL\DC2\EOT\179\EOT\STX&\"= Match any address in the output that exhibits this pattern.\n\ + \\n\ + \\r\n\ + \\ENQ\EOTL\STX\NUL\EOT\DC2\EOT\179\EOT\STX\n\ \\n\ \\r\n\ - \\ENQ\EOTL\STX\NUL\ACK\DC2\EOT\179\EOT\STX\DLE\n\ + \\ENQ\EOTL\STX\NUL\ACK\DC2\EOT\179\EOT\v\EM\n\ \\r\n\ - \\ENQ\EOTL\STX\NUL\SOH\DC2\EOT\179\EOT\DC1\CAN\n\ + \\ENQ\EOTL\STX\NUL\SOH\DC2\EOT\179\EOT\SUB!\n\ \\r\n\ - \\ENQ\EOTL\STX\NUL\ETX\DC2\EOT\179\EOT\ESC\FS\n\ + \\ENQ\EOTL\STX\NUL\ETX\DC2\EOT\179\EOT$%\n\ \I\n\ - \\EOT\EOTL\STX\SOH\DC2\EOT\180\EOT\STX\EM\"; Match any asset in the output that exhibits this pattern.\n\ + \\EOT\EOTL\STX\SOH\DC2\EOT\180\EOT\STX\"\"; Match any asset in the output that exhibits this pattern.\n\ + \\n\ + \\r\n\ + \\ENQ\EOTL\STX\SOH\EOT\DC2\EOT\180\EOT\STX\n\ \\n\ \\r\n\ - \\ENQ\EOTL\STX\SOH\ACK\DC2\EOT\180\EOT\STX\SO\n\ + \\ENQ\EOTL\STX\SOH\ACK\DC2\EOT\180\EOT\v\ETB\n\ \\r\n\ - \\ENQ\EOTL\STX\SOH\SOH\DC2\EOT\180\EOT\SI\DC4\n\ + \\ENQ\EOTL\STX\SOH\SOH\DC2\EOT\180\EOT\CAN\GS\n\ \\r\n\ - \\ENQ\EOTL\STX\SOH\ETX\DC2\EOT\180\EOT\ETB\CAN\n\ + \\ENQ\EOTL\STX\SOH\ETX\DC2\EOT\180\EOT !\n\ \Q\n\ \\STX\EOTM\DC2\ACK\184\EOT\NUL\191\EOT\SOH\SUBC Pattern of a Tx that can be used to evaluate matching predicates.\n\ \\n\ diff --git a/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano_Fields.hs b/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano_Fields.hs index 350c7500ee..4c9127a046 100644 --- a/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano_Fields.hs +++ b/cardano-rpc/gen/Proto/Utxorpc/V1beta/Cardano/Cardano_Fields.hs @@ -856,6 +856,12 @@ maybe'asset :: Data.ProtoLens.Field.HasField s "maybe'asset" a) => Lens.Family2.LensLike' f s a maybe'asset = Data.ProtoLens.Field.field @"maybe'asset" +maybe'assetName :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'assetName" a) => + Lens.Family2.LensLike' f s a +maybe'assetName = Data.ProtoLens.Field.field @"maybe'assetName" maybe'authCommitteeHotCert :: forall f s a. (Prelude.Functor f, @@ -1023,6 +1029,13 @@ maybe'datum :: Data.ProtoLens.Field.HasField s "maybe'datum" a) => Lens.Family2.LensLike' f s a maybe'datum = Data.ProtoLens.Field.field @"maybe'datum" +maybe'delegationPart :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'delegationPart" a) => + Lens.Family2.LensLike' f s a +maybe'delegationPart + = Data.ProtoLens.Field.field @"maybe'delegationPart" maybe'deltaCoin :: forall f s a. (Prelude.Functor f, @@ -1073,6 +1086,13 @@ maybe'exUnits :: Data.ProtoLens.Field.HasField s "maybe'exUnits" a) => Lens.Family2.LensLike' f s a maybe'exUnits = Data.ProtoLens.Field.field @"maybe'exUnits" +maybe'exactAddress :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'exactAddress" a) => + Lens.Family2.LensLike' f s a +maybe'exactAddress + = Data.ProtoLens.Field.field @"maybe'exactAddress" maybe'executionPrices :: forall f s a. (Prelude.Functor f, @@ -1385,6 +1405,12 @@ maybe'payload :: Data.ProtoLens.Field.HasField s "maybe'payload" a) => Lens.Family2.LensLike' f s a maybe'payload = Data.ProtoLens.Field.field @"maybe'payload" +maybe'paymentPart :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'paymentPart" a) => + Lens.Family2.LensLike' f s a +maybe'paymentPart = Data.ProtoLens.Field.field @"maybe'paymentPart" maybe'pledge :: forall f s a. (Prelude.Functor f, @@ -1421,6 +1447,12 @@ maybe'plutusV4 :: Data.ProtoLens.Field.HasField s "maybe'plutusV4" a) => Lens.Family2.LensLike' f s a maybe'plutusV4 = Data.ProtoLens.Field.field @"maybe'plutusV4" +maybe'policyId :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'policyId" a) => + Lens.Family2.LensLike' f s a +maybe'policyId = Data.ProtoLens.Field.field @"maybe'policyId" maybe'poolDeposit :: forall f s a. (Prelude.Functor f, diff --git a/cardano-rpc/gen/Proto/Utxorpc/V1beta/Query/Query.hs b/cardano-rpc/gen/Proto/Utxorpc/V1beta/Query/Query.hs index 80a1a10ec4..d4f91e2d33 100644 --- a/cardano-rpc/gen/Proto/Utxorpc/V1beta/Query/Query.hs +++ b/cardano-rpc/gen/Proto/Utxorpc/V1beta/Query/Query.hs @@ -3631,12 +3631,14 @@ instance Control.DeepSeq.NFData ReadUtxosResponse where * 'Proto.Utxorpc.V1beta.Query.Query_Fields.fieldMask' @:: Lens' SearchUtxosRequest Proto.Google.Protobuf.FieldMask.FieldMask@ * 'Proto.Utxorpc.V1beta.Query.Query_Fields.maybe'fieldMask' @:: Lens' SearchUtxosRequest (Prelude.Maybe Proto.Google.Protobuf.FieldMask.FieldMask)@ * 'Proto.Utxorpc.V1beta.Query.Query_Fields.maxItems' @:: Lens' SearchUtxosRequest Data.Int.Int32@ - * 'Proto.Utxorpc.V1beta.Query.Query_Fields.startToken' @:: Lens' SearchUtxosRequest Data.Text.Text@ -} + * 'Proto.Utxorpc.V1beta.Query.Query_Fields.maybe'maxItems' @:: Lens' SearchUtxosRequest (Prelude.Maybe Data.Int.Int32)@ + * 'Proto.Utxorpc.V1beta.Query.Query_Fields.startToken' @:: Lens' SearchUtxosRequest Data.Text.Text@ + * 'Proto.Utxorpc.V1beta.Query.Query_Fields.maybe'startToken' @:: Lens' SearchUtxosRequest (Prelude.Maybe Data.Text.Text)@ -} data SearchUtxosRequest = SearchUtxosRequest'_constructor {_SearchUtxosRequest'predicate :: !(Prelude.Maybe UtxoPredicate), _SearchUtxosRequest'fieldMask :: !(Prelude.Maybe Proto.Google.Protobuf.FieldMask.FieldMask), - _SearchUtxosRequest'maxItems :: !Data.Int.Int32, - _SearchUtxosRequest'startToken :: !Data.Text.Text, + _SearchUtxosRequest'maxItems :: !(Prelude.Maybe Data.Int.Int32), + _SearchUtxosRequest'startToken :: !(Prelude.Maybe Data.Text.Text), _SearchUtxosRequest'_unknownFields :: !Data.ProtoLens.FieldSet} deriving stock (Prelude.Eq, Prelude.Ord) instance Prelude.Show SearchUtxosRequest where @@ -3674,6 +3676,13 @@ instance Data.ProtoLens.Field.HasField SearchUtxosRequest "maybe'fieldMask" (Pre (\ x__ y__ -> x__ {_SearchUtxosRequest'fieldMask = y__})) Prelude.id instance Data.ProtoLens.Field.HasField SearchUtxosRequest "maxItems" Data.Int.Int32 where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _SearchUtxosRequest'maxItems + (\ x__ y__ -> x__ {_SearchUtxosRequest'maxItems = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField SearchUtxosRequest "maybe'maxItems" (Prelude.Maybe Data.Int.Int32) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -3681,6 +3690,13 @@ instance Data.ProtoLens.Field.HasField SearchUtxosRequest "maxItems" Data.Int.In (\ x__ y__ -> x__ {_SearchUtxosRequest'maxItems = y__})) Prelude.id instance Data.ProtoLens.Field.HasField SearchUtxosRequest "startToken" Data.Text.Text where + fieldOf _ + = (Prelude..) + (Lens.Family2.Unchecked.lens + _SearchUtxosRequest'startToken + (\ x__ y__ -> x__ {_SearchUtxosRequest'startToken = y__})) + (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault) +instance Data.ProtoLens.Field.HasField SearchUtxosRequest "maybe'startToken" (Prelude.Maybe Data.Text.Text) where fieldOf _ = (Prelude..) (Lens.Family2.Unchecked.lens @@ -3692,13 +3708,18 @@ instance Data.ProtoLens.Message SearchUtxosRequest where = Data.Text.pack "utxorpc.v1beta.query.SearchUtxosRequest" packedMessageDescriptor _ = "\n\ - \\DC2SearchUtxosRequest\DC2A\n\ - \\tpredicate\CAN\SOH \SOH(\v2#.utxorpc.v1beta.query.UtxoPredicateR\tpredicate\DC29\n\ + \\DC2SearchUtxosRequest\DC2F\n\ + \\tpredicate\CAN\SOH \SOH(\v2#.utxorpc.v1beta.query.UtxoPredicateH\NULR\tpredicate\136\SOH\SOH\DC29\n\ + \\n\ + \field_mask\CAN\STX \SOH(\v2\SUB.google.protobuf.FieldMaskR\tfieldMask\DC2 \n\ + \\tmax_items\CAN\ETX \SOH(\ENQH\SOHR\bmaxItems\136\SOH\SOH\DC2$\n\ + \\vstart_token\CAN\EOT \SOH(\tH\STXR\n\ + \startToken\136\SOH\SOHB\f\n\ + \\n\ + \_predicateB\f\n\ \\n\ - \field_mask\CAN\STX \SOH(\v2\SUB.google.protobuf.FieldMaskR\tfieldMask\DC2\ESC\n\ - \\tmax_items\CAN\ETX \SOH(\ENQR\bmaxItems\DC2\US\n\ - \\vstart_token\CAN\EOT \SOH(\tR\n\ - \startToken" + \_max_itemsB\SO\n\ + \\f_start_token" packedFileDescriptor _ = packedFileDescriptor fieldsByTag = let @@ -3723,18 +3744,16 @@ instance Data.ProtoLens.Message SearchUtxosRequest where "max_items" (Data.ProtoLens.ScalarField Data.ProtoLens.Int32Field :: Data.ProtoLens.FieldTypeDescriptor Data.Int.Int32) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"maxItems")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'maxItems")) :: Data.ProtoLens.FieldDescriptor SearchUtxosRequest startToken__field_descriptor = Data.ProtoLens.FieldDescriptor "start_token" (Data.ProtoLens.ScalarField Data.ProtoLens.StringField :: Data.ProtoLens.FieldTypeDescriptor Data.Text.Text) - (Data.ProtoLens.PlainField - Data.ProtoLens.Optional - (Data.ProtoLens.Field.field @"startToken")) :: + (Data.ProtoLens.OptionalField + (Data.ProtoLens.Field.field @"maybe'startToken")) :: Data.ProtoLens.FieldDescriptor SearchUtxosRequest in Data.Map.fromList @@ -3750,8 +3769,8 @@ instance Data.ProtoLens.Message SearchUtxosRequest where = SearchUtxosRequest'_constructor {_SearchUtxosRequest'predicate = Prelude.Nothing, _SearchUtxosRequest'fieldMask = Prelude.Nothing, - _SearchUtxosRequest'maxItems = Data.ProtoLens.fieldDefault, - _SearchUtxosRequest'startToken = Data.ProtoLens.fieldDefault, + _SearchUtxosRequest'maxItems = Prelude.Nothing, + _SearchUtxosRequest'startToken = Prelude.Nothing, _SearchUtxosRequest'_unknownFields = []} parseMessage = let @@ -3852,33 +3871,31 @@ instance Data.ProtoLens.Message SearchUtxosRequest where (Data.ProtoLens.Encoding.Bytes.putBytes bs)) Data.ProtoLens.encodeMessage _v)) ((Data.Monoid.<>) - (let - _v = Lens.Family2.view (Data.ProtoLens.Field.field @"maxItems") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 24) - ((Prelude..) - Data.ProtoLens.Encoding.Bytes.putVarInt Prelude.fromIntegral _v)) + (case + Lens.Family2.view (Data.ProtoLens.Field.field @"maybe'maxItems") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 24) + ((Prelude..) + Data.ProtoLens.Encoding.Bytes.putVarInt Prelude.fromIntegral _v)) ((Data.Monoid.<>) - (let - _v - = Lens.Family2.view (Data.ProtoLens.Field.field @"startToken") _x - in - if (Prelude.==) _v Data.ProtoLens.fieldDefault then - Data.Monoid.mempty - else - (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt 34) - ((Prelude..) - (\ bs - -> (Data.Monoid.<>) - (Data.ProtoLens.Encoding.Bytes.putVarInt - (Prelude.fromIntegral (Data.ByteString.length bs))) - (Data.ProtoLens.Encoding.Bytes.putBytes bs)) - Data.Text.Encoding.encodeUtf8 _v)) + (case + Lens.Family2.view + (Data.ProtoLens.Field.field @"maybe'startToken") _x + of + Prelude.Nothing -> Data.Monoid.mempty + (Prelude.Just _v) + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt 34) + ((Prelude..) + (\ bs + -> (Data.Monoid.<>) + (Data.ProtoLens.Encoding.Bytes.putVarInt + (Prelude.fromIntegral (Data.ByteString.length bs))) + (Data.ProtoLens.Encoding.Bytes.putBytes bs)) + Data.Text.Encoding.encodeUtf8 _v)) (Data.ProtoLens.Encoding.Wire.buildFieldSet (Lens.Family2.view Data.ProtoLens.unknownFields _x))))) instance Control.DeepSeq.NFData SearchUtxosRequest where @@ -4592,13 +4609,16 @@ data QueryService = QueryService {} instance Data.ProtoLens.Service.Types.Service QueryService where type ServiceName QueryService = "QueryService" type ServicePackage QueryService = "utxorpc.v1beta.query" - type ServiceMethods QueryService = '["readParams", "readUtxos"] + type ServiceMethods QueryService = '["readParams", + "readUtxos", + "searchUtxos"] packedServiceDescriptor _ = "\n\ \\fQueryService\DC2_\n\ \\n\ \ReadParams\DC2'.utxorpc.v1beta.query.ReadParamsRequest\SUB(.utxorpc.v1beta.query.ReadParamsResponse\DC2\\\n\ - \\tReadUtxos\DC2&.utxorpc.v1beta.query.ReadUtxosRequest\SUB'.utxorpc.v1beta.query.ReadUtxosResponse" + \\tReadUtxos\DC2&.utxorpc.v1beta.query.ReadUtxosRequest\SUB'.utxorpc.v1beta.query.ReadUtxosResponse\DC2b\n\ + \\vSearchUtxos\DC2(.utxorpc.v1beta.query.SearchUtxosRequest\SUB).utxorpc.v1beta.query.SearchUtxosResponse" instance Data.ProtoLens.Service.Types.HasMethodImpl QueryService "readParams" where type MethodName QueryService "readParams" = "ReadParams" type MethodInput QueryService "readParams" = ReadParamsRequest @@ -4609,6 +4629,11 @@ instance Data.ProtoLens.Service.Types.HasMethodImpl QueryService "readUtxos" whe type MethodInput QueryService "readUtxos" = ReadUtxosRequest type MethodOutput QueryService "readUtxos" = ReadUtxosResponse type MethodStreamingType QueryService "readUtxos" = 'Data.ProtoLens.Service.Types.NonStreaming +instance Data.ProtoLens.Service.Types.HasMethodImpl QueryService "searchUtxos" where + type MethodName QueryService "searchUtxos" = "SearchUtxos" + type MethodInput QueryService "searchUtxos" = SearchUtxosRequest + type MethodOutput QueryService "searchUtxos" = SearchUtxosResponse + type MethodStreamingType QueryService "searchUtxos" = 'Data.ProtoLens.Service.Types.NonStreaming packedFileDescriptor :: Data.ByteString.ByteString packedFileDescriptor = "\n\ @@ -4671,14 +4696,19 @@ packedFileDescriptor \\DC1ReadUtxosResponse\DC27\n\ \\ENQitems\CAN\SOH \ETX(\v2!.utxorpc.v1beta.query.AnyUtxoDataR\ENQitems\DC2?\n\ \\n\ - \ledger_tip\CAN\STX \SOH(\v2 .utxorpc.v1beta.query.ChainPointR\tledgerTip\"\208\SOH\n\ - \\DC2SearchUtxosRequest\DC2A\n\ - \\tpredicate\CAN\SOH \SOH(\v2#.utxorpc.v1beta.query.UtxoPredicateR\tpredicate\DC29\n\ + \ledger_tip\CAN\STX \SOH(\v2 .utxorpc.v1beta.query.ChainPointR\tledgerTip\"\139\STX\n\ + \\DC2SearchUtxosRequest\DC2F\n\ + \\tpredicate\CAN\SOH \SOH(\v2#.utxorpc.v1beta.query.UtxoPredicateH\NULR\tpredicate\136\SOH\SOH\DC29\n\ + \\n\ + \field_mask\CAN\STX \SOH(\v2\SUB.google.protobuf.FieldMaskR\tfieldMask\DC2 \n\ + \\tmax_items\CAN\ETX \SOH(\ENQH\SOHR\bmaxItems\136\SOH\SOH\DC2$\n\ + \\vstart_token\CAN\EOT \SOH(\tH\STXR\n\ + \startToken\136\SOH\SOHB\f\n\ + \\n\ + \_predicateB\f\n\ \\n\ - \field_mask\CAN\STX \SOH(\v2\SUB.google.protobuf.FieldMaskR\tfieldMask\DC2\ESC\n\ - \\tmax_items\CAN\ETX \SOH(\ENQR\bmaxItems\DC2\US\n\ - \\vstart_token\CAN\EOT \SOH(\tR\n\ - \startToken\"\174\SOH\n\ + \_max_itemsB\SO\n\ + \\f_start_token\"\174\SOH\n\ \\DC3SearchUtxosResponse\DC27\n\ \\ENQitems\CAN\SOH \ETX(\v2!.utxorpc.v1beta.query.AnyUtxoDataR\ENQitems\DC2?\n\ \\n\ @@ -4711,14 +4741,15 @@ packedFileDescriptor \\SOReadTxResponse\DC20\n\ \\STXtx\CAN\SOH \SOH(\v2 .utxorpc.v1beta.query.AnyChainTxR\STXtx\DC2?\n\ \\n\ - \ledger_tip\CAN\STX \SOH(\v2 .utxorpc.v1beta.query.ChainPointR\tledgerTip2\205\SOH\n\ + \ledger_tip\CAN\STX \SOH(\v2 .utxorpc.v1beta.query.ChainPointR\tledgerTip2\177\STX\n\ \\fQueryService\DC2_\n\ \\n\ \ReadParams\DC2'.utxorpc.v1beta.query.ReadParamsRequest\SUB(.utxorpc.v1beta.query.ReadParamsResponse\DC2\\\n\ - \\tReadUtxos\DC2&.utxorpc.v1beta.query.ReadUtxosRequest\SUB'.utxorpc.v1beta.query.ReadUtxosResponseB\152\SOH\n\ + \\tReadUtxos\DC2&.utxorpc.v1beta.query.ReadUtxosRequest\SUB'.utxorpc.v1beta.query.ReadUtxosResponse\DC2b\n\ + \\vSearchUtxos\DC2(.utxorpc.v1beta.query.SearchUtxosRequest\SUB).utxorpc.v1beta.query.SearchUtxosResponseB\152\SOH\n\ \\CANcom.utxorpc.v1beta.queryB\n\ - \QueryProtoP\SOH\162\STX\ETXUVQ\170\STX\DC4Utxorpc.V1beta.Query\202\STX\DC4Utxorpc\\V1beta\\Query\226\STX Utxorpc\\V1beta\\Query\\GPBMetadata\234\STX\SYNUtxorpc::V1beta::QueryJ\234\&9\n\ - \\a\DC2\ENQ\STX\NUL\176\SOH\SOH\n\ + \QueryProtoP\SOH\162\STX\ETXUVQ\170\STX\DC4Utxorpc.V1beta.Query\202\STX\DC4Utxorpc\\V1beta\\Query\226\STX Utxorpc\\V1beta\\Query\\GPBMetadata\234\STX\SYNUtxorpc::V1beta::QueryJ\246:\n\ + \\a\DC2\ENQ\STX\NUL\177\SOH\SOH\n\ \9\n\ \\SOH\f\DC2\ETX\STX\NUL\DC22// A consistent view of the state of the ledger\n\ \\n\ @@ -5153,14 +5184,17 @@ packedFileDescriptor \\n\ \\ETX\EOT\SI\SOH\DC2\ETXp\b\SUB\n\ \)\n\ - \\EOT\EOT\SI\STX\NUL\DC2\ETXq\STX\RS\"\FS Pattern to match UTxOs by.\n\ + \\EOT\EOT\SI\STX\NUL\DC2\ETXq\STX'\"\FS Pattern to match UTxOs by.\n\ \\n\ \\f\n\ - \\ENQ\EOT\SI\STX\NUL\ACK\DC2\ETXq\STX\SI\n\ + \\ENQ\EOT\SI\STX\NUL\EOT\DC2\ETXq\STX\n\ + \\n\ + \\f\n\ + \\ENQ\EOT\SI\STX\NUL\ACK\DC2\ETXq\v\CAN\n\ \\f\n\ - \\ENQ\EOT\SI\STX\NUL\SOH\DC2\ETXq\DLE\EM\n\ + \\ENQ\EOT\SI\STX\NUL\SOH\DC2\ETXq\EM\"\n\ \\f\n\ - \\ENQ\EOT\SI\STX\NUL\ETX\DC2\ETXq\FS\GS\n\ + \\ENQ\EOT\SI\STX\NUL\ETX\DC2\ETXq%&\n\ \7\n\ \\EOT\EOT\SI\STX\SOH\DC2\ETXr\STX+\"* Field mask to selectively return fields.\n\ \\n\ @@ -5171,23 +5205,29 @@ packedFileDescriptor \\f\n\ \\ENQ\EOT\SI\STX\SOH\ETX\DC2\ETXr)*\n\ \5\n\ - \\EOT\EOT\SI\STX\STX\DC2\ETXs\STX\SYN\"( The maximum number of items to return.\n\ + \\EOT\EOT\SI\STX\STX\DC2\ETXs\STX\US\"( The maximum number of items to return.\n\ + \\n\ + \\f\n\ + \\ENQ\EOT\SI\STX\STX\EOT\DC2\ETXs\STX\n\ \\n\ \\f\n\ - \\ENQ\EOT\SI\STX\STX\ENQ\DC2\ETXs\STX\a\n\ + \\ENQ\EOT\SI\STX\STX\ENQ\DC2\ETXs\v\DLE\n\ \\f\n\ - \\ENQ\EOT\SI\STX\STX\SOH\DC2\ETXs\b\DC1\n\ + \\ENQ\EOT\SI\STX\STX\SOH\DC2\ETXs\DC1\SUB\n\ \\f\n\ - \\ENQ\EOT\SI\STX\STX\ETX\DC2\ETXs\DC4\NAK\n\ + \\ENQ\EOT\SI\STX\STX\ETX\DC2\ETXs\GS\RS\n\ \R\n\ - \\EOT\EOT\SI\STX\ETX\DC2\ETXt\STX\EM\"E The next_page_token value returned from a previous request, if any.\n\ + \\EOT\EOT\SI\STX\ETX\DC2\ETXt\STX\"\"E The next_page_token value returned from a previous request, if any.\n\ \\n\ \\f\n\ - \\ENQ\EOT\SI\STX\ETX\ENQ\DC2\ETXt\STX\b\n\ + \\ENQ\EOT\SI\STX\ETX\EOT\DC2\ETXt\STX\n\ + \\n\ + \\f\n\ + \\ENQ\EOT\SI\STX\ETX\ENQ\DC2\ETXt\v\DC1\n\ \\f\n\ - \\ENQ\EOT\SI\STX\ETX\SOH\DC2\ETXt\t\DC4\n\ + \\ENQ\EOT\SI\STX\ETX\SOH\DC2\ETXt\DC2\GS\n\ \\f\n\ - \\ENQ\EOT\SI\STX\ETX\ETX\DC2\ETXt\ETB\CAN\n\ + \\ENQ\EOT\SI\STX\ETX\ETX\DC2\ETXt !\n\ \O\n\ \\STX\EOT\DLE\DC2\EOTx\NUL|\SOH\SUBC Response containing the UTxOs that match the requested addresses.\n\ \\n\ @@ -5394,7 +5434,7 @@ packedFileDescriptor \\r\n\ \\ENQ\EOT\SYN\STX\SOH\ETX\DC2\EOT\165\SOH\SUB\ESC\n\ \G\n\ - \\STX\ACK\NUL\DC2\ACK\169\SOH\NUL\176\SOH\SOH\SUB9 Service definition for querying the state of the chain.\n\ + \\STX\ACK\NUL\DC2\ACK\169\SOH\NUL\177\SOH\SOH\SUB9 Service definition for querying the state of the chain.\n\ \\n\ \\v\n\ \\ETX\ACK\NUL\SOH\DC2\EOT\169\SOH\b\DC4\n\ @@ -5415,4 +5455,13 @@ packedFileDescriptor \\r\n\ \\ENQ\ACK\NUL\STX\SOH\STX\DC2\EOT\171\SOH\DLE \n\ \\r\n\ - \\ENQ\ACK\NUL\STX\SOH\ETX\DC2\EOT\171\SOH+ Lens.Family2.LensLike' f s a maybe'match = Data.ProtoLens.Field.field @"maybe'match" +maybe'maxItems :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'maxItems" a) => + Lens.Family2.LensLike' f s a +maybe'maxItems = Data.ProtoLens.Field.field @"maybe'maxItems" maybe'params :: forall f s a. (Prelude.Functor f, @@ -173,6 +179,12 @@ maybe'predicate :: Data.ProtoLens.Field.HasField s "maybe'predicate" a) => Lens.Family2.LensLike' f s a maybe'predicate = Data.ProtoLens.Field.field @"maybe'predicate" +maybe'startToken :: + forall f s a. + (Prelude.Functor f, + Data.ProtoLens.Field.HasField s "maybe'startToken" a) => + Lens.Family2.LensLike' f s a +maybe'startToken = Data.ProtoLens.Field.field @"maybe'startToken" maybe'summary :: forall f s a. (Prelude.Functor f, diff --git a/cardano-rpc/proto/utxorpc/v1beta/cardano/cardano.proto b/cardano-rpc/proto/utxorpc/v1beta/cardano/cardano.proto index 05c6a803b8..a0109f0519 100644 --- a/cardano-rpc/proto/utxorpc/v1beta/cardano/cardano.proto +++ b/cardano-rpc/proto/utxorpc/v1beta/cardano/cardano.proto @@ -516,15 +516,15 @@ message UpdateDRepCert { // Pattern of an address that can be used to evaluate matching predicates. message AddressPattern { - bytes exact_address = 1; // The address should match this exact address value. - bytes payment_part = 2; // The payment part of the address should match this value. - bytes delegation_part = 3; // The delegation part of the address should match this value. + optional bytes exact_address = 1; // The address should match this exact address value. + optional bytes payment_part = 2; // The payment part of the address should match this value. + optional bytes delegation_part = 3; // The delegation part of the address should match this value. } // Pattern of a native asset that can be used to evaluate matching predicates. message AssetPattern { - bytes policy_id = 1; // The asset should belong to this policy id - bytes asset_name = 2; // The asset should present this name + optional bytes policy_id = 1; // The asset should belong to this policy id + optional bytes asset_name = 2; // The asset should present this name } // Pattern of a certificate that can be used to evaluate matching predicates. @@ -561,8 +561,8 @@ message PoolRetirementPattern { // Pattern of a tx output that can be used to evaluate matching predicates. message TxOutputPattern { - AddressPattern address = 1; // Match any address in the output that exhibits this pattern. - AssetPattern asset = 2; // Match any asset in the output that exhibits this pattern. + optional AddressPattern address = 1; // Match any address in the output that exhibits this pattern. + optional AssetPattern asset = 2; // Match any asset in the output that exhibits this pattern. } // Pattern of a Tx that can be used to evaluate matching predicates. diff --git a/cardano-rpc/proto/utxorpc/v1beta/query/query.proto b/cardano-rpc/proto/utxorpc/v1beta/query/query.proto index 302941e36a..fa179849d5 100644 --- a/cardano-rpc/proto/utxorpc/v1beta/query/query.proto +++ b/cardano-rpc/proto/utxorpc/v1beta/query/query.proto @@ -111,10 +111,10 @@ message ReadUtxosResponse { // Request to search for UTxO based on a pattern. message SearchUtxosRequest { - UtxoPredicate predicate = 1; // Pattern to match UTxOs by. + optional UtxoPredicate predicate = 1; // Pattern to match UTxOs by. google.protobuf.FieldMask field_mask = 2; // Field mask to selectively return fields. - int32 max_items = 3; // The maximum number of items to return. - string start_token = 4; // The next_page_token value returned from a previous request, if any. + optional int32 max_items = 3; // The maximum number of items to return. + optional string start_token = 4; // The next_page_token value returned from a previous request, if any. } // Response containing the UTxOs that match the requested addresses. @@ -170,6 +170,7 @@ message ReadTxResponse { service QueryService { rpc ReadParams(ReadParamsRequest) returns (ReadParamsResponse); // Get overall chain state. rpc ReadUtxos(ReadUtxosRequest) returns (ReadUtxosResponse); // Read specific UTxOs by reference. + rpc SearchUtxos(SearchUtxosRequest) returns (SearchUtxosResponse); // Search for UTxO based on a pattern. // TODO: decide if we want to expand the scope // rpc DumpUtxos(ReadUtxosRequest) returns (stream ReadUtxosResponse); // Dump all available utxos diff --git a/cardano-rpc/src/Cardano/Rpc/Server.hs b/cardano-rpc/src/Cardano/Rpc/Server.hs index a7469b7103..c165ff0815 100644 --- a/cardano-rpc/src/Cardano/Rpc/Server.hs +++ b/cardano-rpc/src/Cardano/Rpc/Server.hs @@ -56,6 +56,7 @@ methodsUtxoRpc methodsUtxoRpc = Method (mkNonStreaming $ wrapInSpan TraceRpcQueryParamsSpan . readParamsMethod) . Method (mkNonStreaming $ wrapInSpan TraceRpcQueryReadUtxosSpan . readUtxosMethod) + . Method (mkNonStreaming $ wrapInSpan TraceRpcQuerySearchUtxosSpan . searchUtxosMethod) $ NoMoreMethods methodsUtxoRpcSubmit diff --git a/cardano-rpc/src/Cardano/Rpc/Server/Internal/Tracing.hs b/cardano-rpc/src/Cardano/Rpc/Server/Internal/Tracing.hs index 1e421c1276..79dbb31343 100644 --- a/cardano-rpc/src/Cardano/Rpc/Server/Internal/Tracing.hs +++ b/cardano-rpc/src/Cardano/Rpc/Server/Internal/Tracing.hs @@ -27,6 +27,8 @@ data TraceRpcQuery TraceRpcQueryParamsSpan TraceSpanEvent | -- | Span trace marking ReadUtxos query TraceRpcQueryReadUtxosSpan TraceSpanEvent + | -- | Span trace marking SearchUtxos query + TraceRpcQuerySearchUtxosSpan TraceSpanEvent deriving Show instance Pretty TraceRpc where @@ -53,6 +55,8 @@ instance Pretty TraceRpcQuery where TraceRpcQueryParamsSpan (SpanEnd _) -> "Finished query params method" TraceRpcQueryReadUtxosSpan (SpanBegin _) -> "Started query read UTXO method" TraceRpcQueryReadUtxosSpan (SpanEnd _) -> "Finished query read UTXO method" + TraceRpcQuerySearchUtxosSpan (SpanBegin _) -> "Started query search UTXO method" + TraceRpcQuerySearchUtxosSpan (SpanEnd _) -> "Finished query search UTXO method" instance Error TraceRpcQuery where prettyError = pretty diff --git a/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Predicate.hs b/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Predicate.hs new file mode 100644 index 0000000000..8b65e71787 --- /dev/null +++ b/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Predicate.hs @@ -0,0 +1,123 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Cardano.Rpc.Server.Internal.UtxoRpc.Predicate + ( matchesUtxoPredicate + , extractAddressesFromPredicate + , matchesAddressPattern + , matchesAssetPattern + , matchesTxOutputPattern + , matchesAnyUtxoPattern + , serialisePaymentCredential + , serialiseStakeCredential + ) +where + +import Cardano.Api.Address +import Cardano.Api.Serialise.Raw +import Cardano.Api.Tx +import Cardano.Api.Value +import Cardano.Rpc.Proto.Api.UtxoRpc.Query qualified as U5c +import Cardano.Rpc.Proto.Api.UtxoRpc.Query qualified as UtxoRpc + +import RIO hiding (toList) + +import Control.Monad (guard) +import Data.ByteString qualified as BS +import Data.Set (Set) +import Data.Set qualified as Set +import GHC.IsList + +-- | Check if a UTxO entry matches a 'UtxoPredicate'. +-- All present fields are combined with AND logic. +matchesUtxoPredicate + :: UtxoRpc.UtxoPredicate + -> TxOut CtxUTxO era + -> Bool +matchesUtxoPredicate p txOut = + all (`matchesAnyUtxoPattern` txOut) (p ^. U5c.maybe'match) + && not (any (`matchesUtxoPredicate` txOut) (p ^. U5c.not)) + && all (`matchesUtxoPredicate` txOut) (p ^. U5c.allOf) + && (null (p ^. U5c.anyOf) || any (`matchesUtxoPredicate` txOut) (p ^. U5c.anyOf)) + +matchesAnyUtxoPattern + :: UtxoRpc.AnyUtxoPattern + -> TxOut CtxUTxO era + -> Bool +matchesAnyUtxoPattern pat txOut = + all (`matchesTxOutputPattern` txOut) (pat ^. U5c.maybe'cardano) + +matchesTxOutputPattern + :: UtxoRpc.TxOutputPattern + -> TxOut CtxUTxO era + -> Bool +matchesTxOutputPattern pat (TxOut addrInEra txOutValue _datum _script) = + all (`matchesAddressPattern` addrInEra) (pat ^. U5c.maybe'address) + && all (`matchesAssetPattern` txOutValueToValue txOutValue) (pat ^. U5c.maybe'asset) + +matchesAddressPattern + :: UtxoRpc.AddressPattern + -> AddressInEra era + -> Bool +matchesAddressPattern pat addr = + exactMatch && paymentMatch && delegationMatch + where + matchesRawField field actual = BS.null field || field == actual + + exactMatch = case addr of + AddressInEra ByronAddressInAnyEra a -> matchesRawField (pat ^. U5c.exactAddress) $ serialiseToRawBytes a + AddressInEra ShelleyAddressInEra{} a -> matchesRawField (pat ^. U5c.exactAddress) $ serialiseToRawBytes a + paymentMatch = case addr of + AddressInEra ShelleyAddressInEra{} (ShelleyAddress _ payCred _) -> + matchesRawField (pat ^. U5c.paymentPart) . serialisePaymentCredential $ fromShelleyPaymentCredential payCred + _ -> BS.null $ pat ^. U5c.paymentPart + delegationMatch = case addr of + AddressInEra ShelleyAddressInEra{} (ShelleyAddress _ _ stakeRef) -> + case fromShelleyStakeReference stakeRef of + StakeAddressByValue cred -> + matchesRawField (pat ^. U5c.delegationPart) $ serialiseStakeCredential cred + _ -> BS.null $ pat ^. U5c.delegationPart + _ -> BS.null $ pat ^. U5c.delegationPart + +serialisePaymentCredential :: PaymentCredential -> ByteString +serialisePaymentCredential (PaymentCredentialByKey h) = serialiseToRawBytes h +serialisePaymentCredential (PaymentCredentialByScript h) = serialiseToRawBytes h + +serialiseStakeCredential :: StakeCredential -> ByteString +serialiseStakeCredential (StakeCredentialByKey h) = serialiseToRawBytes h +serialiseStakeCredential (StakeCredentialByScript h) = serialiseToRawBytes h + +matchesAssetPattern + :: UtxoRpc.AssetPattern + -> Value + -> Bool +matchesAssetPattern pat value = + any matchesEntry (toList value) + where + pid = pat ^. U5c.policyId + aname = pat ^. U5c.assetName + matchesEntry (AssetId pId aName, Quantity qty) = + (BS.null pid || serialiseToRawBytes pId == pid) + && (BS.null aname || serialiseToRawBytes aName == aname) + && qty > 0 + matchesEntry (AdaAssetId, _) = False + +-- | Try to extract a set of exact addresses from the predicate for use with 'QueryUTxOByAddress'. +-- Returns 'Just' if the optimization is applicable, 'Nothing' otherwise. +extractAddressesFromPredicate :: UtxoRpc.UtxoPredicate -> Maybe (Set AddressAny) +extractAddressesFromPredicate p = + case (p ^. U5c.maybe'match, p ^. U5c.not, p ^. U5c.allOf, p ^. U5c.anyOf) of + (Just pat, [], [], []) -> extractAddressFromPattern pat + (Nothing, [], [], anyPreds@(_ : _)) -> + Set.unions <$> traverse extractAddressesFromPredicate anyPreds + _ -> Nothing + where + extractAddressFromPattern :: UtxoRpc.AnyUtxoPattern -> Maybe (Set AddressAny) + extractAddressFromPattern pat = do + txoPat <- pat ^. U5c.maybe'cardano + addrPat <- txoPat ^. U5c.maybe'address + let exact = addrPat ^. U5c.exactAddress + guard $ not (BS.null exact) + addrAny <- either (const Nothing) Just $ deserialiseFromRawBytes AsAddressAny exact + pure $ Set.singleton addrAny diff --git a/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Query.hs b/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Query.hs index 96fce5ef35..8fed3cd228 100644 --- a/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Query.hs +++ b/cardano-rpc/src/Cardano/Rpc/Server/Internal/UtxoRpc/Query.hs @@ -11,6 +11,7 @@ module Cardano.Rpc.Server.Internal.UtxoRpc.Query ( readParamsMethod , readUtxosMethod + , searchUtxosMethod ) where @@ -21,13 +22,17 @@ import Cardano.Rpc.Proto.Api.UtxoRpc.Query qualified as UtxoRpc import Cardano.Rpc.Server.Internal.Error import Cardano.Rpc.Server.Internal.Monad import Cardano.Rpc.Server.Internal.Orphans () +import Cardano.Rpc.Server.Internal.UtxoRpc.Predicate import Cardano.Rpc.Server.Internal.UtxoRpc.Type import RIO hiding (toList) import Data.Default +import Data.List (sortBy) import Data.ProtoLens (defMessage) +import Data.Text qualified as T import GHC.IsList +import Network.GRPC.Common.Protobuf (getProto) import Network.GRPC.Spec readParamsMethod @@ -63,9 +68,6 @@ readUtxosMethod req = do utxoFilter <- if not (null $ req ^. U5c.keys) then QueryUTxOByTxIn . fromList <$> mapM txoRefToTxIn (req ^. U5c.keys) - -- TODO: reimplement this part as SearchUtxosRequest - -- \| Just addressesProto <- req ^. U5c.maybe'cardanoAddresses -> - -- QueryUTxOByAddress . fromList <$> mapM readAddress (addressesProto ^. U5c.items) else pure QueryUTxOWhole nodeConnInfo <- grab @@ -89,7 +91,69 @@ readUtxosMethod req = do txId' <- throwEither $ deserialiseFromRawBytes AsTxId $ r ^. U5c.hash pure $ TxIn txId' (TxIx . fromIntegral $ r ^. U5c.index) --- TODO: reimplement this part as SearchUtxosRequest --- readAddress :: MonadRpc e m => ByteString -> m AddressAny --- readAddress = --- throwEither . first stringException . P.runParser parseAddressAny <=< throwEither . T.decodeUtf8' +searchUtxosMethod + :: MonadRpc e m + => Proto UtxoRpc.SearchUtxosRequest + -> m (Proto UtxoRpc.SearchUtxosResponse) +searchUtxosMethod req = do + let mPredicate = fmap getProto $ req ^. U5c.maybe'predicate + maxItems = req ^. U5c.maxItems + startToken = req ^. U5c.startToken + + -- Determine query strategy: use address-based query if possible, otherwise fetch whole UTxO + let utxoFilter = case mPredicate >>= extractAddressesFromPredicate of + Just addrs | not (null addrs) -> QueryUTxOByAddress addrs + _ -> QueryUTxOWhole + + nodeConnInfo <- grab + AnyCardanoEra era <- liftIO . throwExceptT $ determineEra nodeConnInfo + eon <- forEraInEon @Era era (error "Minimum Conway era required") pure + + let target = VolatileTip + (utxo, chainPoint, blockNo) <- liftIO . (throwEither =<<) $ executeLocalStateQueryExpr nodeConnInfo target $ do + utxo <- throwEither =<< throwEither =<< queryUtxo (convert eon) utxoFilter + chainPoint <- throwEither =<< queryChainPoint + blockNo <- throwEither =<< queryChainBlockNo + pure (utxo, chainPoint, blockNo) + + -- Apply predicate filtering on the result + let filtered = case mPredicate of + Nothing -> toList utxo + Just p -> + filter (\(_txIn, txOut) -> obtainCommonConstraints eon (matchesUtxoPredicate p txOut)) (toList utxo) + + -- Sort by TxIn for deterministic pagination + let sorted = sortBy (compare `on` fst) filtered + + -- Apply pagination: skip past start_token, then take max_items + let afterToken = case startToken of + t | T.null t -> sorted + _ -> dropWhile (\(txIn, _) -> encodeTxInToken txIn <= startToken) sorted + limit = if maxItems > 0 then fromIntegral maxItems else 100 -- default page size + page = take limit afterToken + nextTok = + if length page >= limit && length afterToken > limit + then case lastMaybe page of + Just (lastTxIn, _) -> encodeTxInToken lastTxIn + Nothing -> "" + else "" + + pure $ + defMessage + & U5c.ledgerTip .~ mkChainPointMsg chainPoint blockNo + & U5c.items .~ obtainCommonConstraints eon (map (uncurry txInTxOutToAnyUtxoData) page) + & U5c.nextToken .~ nextTok + where + txInTxOutToAnyUtxoData :: IsEra era => TxIn -> TxOut CtxUTxO era -> Proto UtxoRpc.AnyUtxoData + txInTxOutToAnyUtxoData txIn txOut = + defMessage + & U5c.txoRef .~ inject txIn + & U5c.cardano .~ txOutToUtxoRpcTxOutput txOut + + encodeTxInToken :: TxIn -> T.Text + encodeTxInToken (TxIn txId (TxIx ix)) = + serialiseToRawBytesHexText txId <> "#" <> T.pack (show ix) + + lastMaybe :: [a] -> Maybe a + lastMaybe [] = Nothing + lastMaybe xs = Just (last xs) diff --git a/cardano-rpc/test/cardano-rpc-test/Test/Cardano/Rpc/Predicate.hs b/cardano-rpc/test/cardano-rpc-test/Test/Cardano/Rpc/Predicate.hs new file mode 100644 index 0000000000..582342f7b2 --- /dev/null +++ b/cardano-rpc/test/cardano-rpc-test/Test/Cardano/Rpc/Predicate.hs @@ -0,0 +1,421 @@ +{-# LANGUAGE GADTs #-} +{-# LANGUAGE NumericUnderscores #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} + +module Test.Cardano.Rpc.Predicate where + +import Cardano.Api.Address +import Cardano.Api.Era (MaryEraOnwards (..), ShelleyBasedEra) +import Cardano.Api.Experimental.Era +import Cardano.Api.Plutus (ReferenceScript (..)) +import Cardano.Api.Serialise.Raw +import Cardano.Api.Tx +import Cardano.Api.Value +import Cardano.Rpc.Proto.Api.UtxoRpc.Query qualified as U5c +import Cardano.Rpc.Server.Internal.UtxoRpc.Predicate + +import RIO + +import Data.ByteString qualified as BS +import Data.ProtoLens (defMessage) +import Data.Set qualified as Set + +import Test.Gen.Cardano.Api.Typed + ( genAddressInEra + , genAddressShelley + , genAssetName + , genNetworkId + , genPaymentCredential + , genPolicyId + , genPositiveQuantity + , genStakeAddressReference + , genStakeCredential + , genTxOutUTxOContext + ) + +import Hedgehog +import Hedgehog qualified as H + +-- --------------------------------------------------------------------------- +-- Helpers +-- --------------------------------------------------------------------------- + +sbe :: ShelleyBasedEra ConwayEra +sbe = convert ConwayEra + +genShelleyTxOut :: Gen (TxOut CtxUTxO ConwayEra) +genShelleyTxOut = genTxOutUTxOContext sbe + +-- | Generate a Value that contains at least one non-Ada native asset with positive quantity. +genValueWithNativeAsset :: Gen (Value, AssetId) +genValueWithNativeAsset = do + pid <- genPolicyId + aname <- genAssetName + qty <- genPositiveQuantity + let aid = AssetId pid aname + val = valueFromList [(AdaAssetId, Quantity 2_000_000), (aid, qty)] + pure (val, aid) + +-- | Wrap a TxOutputPattern in a UtxoPredicate via match.cardano. +wrapInPredicate :: U5c.TxOutputPattern -> U5c.UtxoPredicate +wrapInPredicate pat = + defMessage + & U5c.match + .~ ( defMessage + & U5c.cardano .~ pat + ) + +-- | Serialise an AddressInEra to raw bytes. +serialiseAddr :: AddressInEra ConwayEra -> ByteString +serialiseAddr (AddressInEra ByronAddressInAnyEra a) = serialiseToRawBytes a +serialiseAddr (AddressInEra ShelleyAddressInEra{} a) = serialiseToRawBytes a + +-- | Build an AddressPattern with exact address bytes. +mkExactAddressPattern :: AddressInEra ConwayEra -> U5c.AddressPattern +mkExactAddressPattern addr = + defMessage & U5c.exactAddress .~ serialiseAddr addr + +-- | Build an AddressPattern matching by payment credential. +mkPaymentPattern :: PaymentCredential -> U5c.AddressPattern +mkPaymentPattern cred = + defMessage & U5c.paymentPart .~ serialisePaymentCredential cred + +-- | Build an AddressPattern matching by delegation credential. +mkDelegationPattern :: StakeCredential -> U5c.AddressPattern +mkDelegationPattern cred = + defMessage & U5c.delegationPart .~ serialiseStakeCredential cred + +-- | Build an AssetPattern with given policyId. +mkPolicyPattern :: PolicyId -> U5c.AssetPattern +mkPolicyPattern pid = + defMessage & U5c.policyId .~ serialiseToRawBytes pid + +-- | Build an AssetPattern with both policyId and assetName. +mkFullAssetPattern :: PolicyId -> AssetName -> U5c.AssetPattern +mkFullAssetPattern pid aname = + defMessage + & U5c.policyId .~ serialiseToRawBytes pid + & U5c.assetName .~ serialiseToRawBytes aname + +-- | Build a TxOutputPattern from an address pattern. +mkTxOutputPatternAddr :: U5c.AddressPattern -> U5c.TxOutputPattern +mkTxOutputPatternAddr ap = + defMessage & U5c.address .~ ap + +-- | Build a TxOutputPattern from an asset pattern. +mkTxOutputPatternAsset :: U5c.AssetPattern -> U5c.TxOutputPattern +mkTxOutputPatternAsset ap = + defMessage & U5c.asset .~ ap + +-- | Build a TxOutputPattern with both address and asset patterns. +mkTxOutputPatternBoth :: U5c.AddressPattern -> U5c.AssetPattern -> U5c.TxOutputPattern +mkTxOutputPatternBoth ap assetP = + defMessage + & U5c.address .~ ap + & U5c.asset .~ assetP + +-- --------------------------------------------------------------------------- +-- A. Default/empty patterns match everything +-- --------------------------------------------------------------------------- + +hprop_default_predicate_matches_everything :: Property +hprop_default_predicate_matches_everything = H.property $ do + txOut <- forAll genShelleyTxOut + H.assert $ matchesUtxoPredicate defMessage txOut + +hprop_default_address_pattern_matches_any_address :: Property +hprop_default_address_pattern_matches_any_address = H.property $ do + addr <- forAll $ genAddressInEra sbe + H.assert $ matchesAddressPattern defMessage addr + +hprop_default_asset_pattern_matches_value_with_native_asset :: Property +hprop_default_asset_pattern_matches_value_with_native_asset = H.property $ do + (val, _aid) <- forAll genValueWithNativeAsset + H.assert $ matchesAssetPattern defMessage val + +-- --------------------------------------------------------------------------- +-- B. Address matching — exact +-- --------------------------------------------------------------------------- + +hprop_exact_address_matches_same :: Property +hprop_exact_address_matches_same = H.property $ do + addr <- forAll $ genAddressInEra sbe + let pat = mkExactAddressPattern addr + H.assert $ matchesAddressPattern pat addr + +hprop_exact_address_rejects_different :: Property +hprop_exact_address_rejects_different = H.property $ do + addr1 <- forAll $ genAddressInEra sbe + addr2 <- forAll $ genAddressInEra sbe + let pat = mkExactAddressPattern addr1 + -- Two independently generated Shelley addresses are almost certainly different + when (serialiseAddr addr1 /= serialiseAddr addr2) $ + H.assert $ + not $ + matchesAddressPattern pat addr2 + +-- --------------------------------------------------------------------------- +-- C. Address matching — payment & delegation parts +-- --------------------------------------------------------------------------- + +hprop_payment_part_matches_same_credential :: Property +hprop_payment_part_matches_same_credential = H.property $ do + cred <- forAll genPaymentCredential + nw <- forAll genNetworkId + stakeRef <- forAll genStakeAddressReference + let shelleyAddr = makeShelleyAddress nw cred stakeRef + addr = shelleyAddressInEra sbe shelleyAddr + pat = mkPaymentPattern cred + H.assert $ matchesAddressPattern pat addr + +hprop_payment_part_rejects_different_credential :: Property +hprop_payment_part_rejects_different_credential = H.property $ do + cred1 <- forAll genPaymentCredential + cred2 <- forAll genPaymentCredential + nw <- forAll genNetworkId + stakeRef <- forAll genStakeAddressReference + let shelleyAddr = makeShelleyAddress nw cred1 stakeRef + addr = shelleyAddressInEra sbe shelleyAddr + pat = mkPaymentPattern cred2 + when (serialisePaymentCredential cred1 /= serialisePaymentCredential cred2) $ + H.assert $ + not $ + matchesAddressPattern pat addr + +hprop_delegation_part_matches_same_credential :: Property +hprop_delegation_part_matches_same_credential = H.property $ do + stakeCred <- forAll genStakeCredential + payCred <- forAll genPaymentCredential + nw <- forAll genNetworkId + let stakeRef = StakeAddressByValue stakeCred + shelleyAddr = makeShelleyAddress nw payCred stakeRef + addr = shelleyAddressInEra sbe shelleyAddr + pat = mkDelegationPattern stakeCred + H.assert $ matchesAddressPattern pat addr + +hprop_delegation_part_rejects_when_no_stake_address :: Property +hprop_delegation_part_rejects_when_no_stake_address = H.property $ do + stakeCred <- forAll genStakeCredential + payCred <- forAll genPaymentCredential + nw <- forAll genNetworkId + let shelleyAddr = makeShelleyAddress nw payCred NoStakeAddress + addr = shelleyAddressInEra sbe shelleyAddr + pat = mkDelegationPattern stakeCred + H.assert $ not $ matchesAddressPattern pat addr + +hprop_address_pattern_all_fields_must_match :: Property +hprop_address_pattern_all_fields_must_match = H.property $ do + payCred <- forAll genPaymentCredential + stakeCred <- forAll genStakeCredential + nw <- forAll genNetworkId + let stakeRef = StakeAddressByValue stakeCred + shelleyAddr = makeShelleyAddress nw payCred stakeRef + addr = shelleyAddressInEra sbe shelleyAddr + -- Pattern with all three fields matching + pat = + defMessage + & U5c.exactAddress .~ serialiseToRawBytes shelleyAddr + & U5c.paymentPart .~ serialisePaymentCredential payCred + & U5c.delegationPart .~ serialiseStakeCredential stakeCred + -- Should match when all fields agree + H.assert $ matchesAddressPattern pat addr + -- Break the payment part → fail + otherPayCred <- forAll genPaymentCredential + when (serialisePaymentCredential payCred /= serialisePaymentCredential otherPayCred) $ do + let brokenPat = pat & U5c.paymentPart .~ serialisePaymentCredential otherPayCred + H.assert $ not $ matchesAddressPattern brokenPat addr + +-- --------------------------------------------------------------------------- +-- D. Asset matching +-- --------------------------------------------------------------------------- + +hprop_asset_pattern_matches_by_policy :: Property +hprop_asset_pattern_matches_by_policy = H.property $ do + (val, AssetId pid _aname) <- forAll genValueWithNativeAsset + let pat = mkPolicyPattern pid + H.assert $ matchesAssetPattern pat val + +hprop_asset_pattern_matches_by_policy_and_name :: Property +hprop_asset_pattern_matches_by_policy_and_name = H.property $ do + (val, AssetId pid aname) <- forAll genValueWithNativeAsset + let pat = mkFullAssetPattern pid aname + H.assert $ matchesAssetPattern pat val + +hprop_asset_pattern_rejects_wrong_policy :: Property +hprop_asset_pattern_rejects_wrong_policy = H.property $ do + (val, AssetId pid _aname) <- forAll genValueWithNativeAsset + otherPid <- forAll genPolicyId + when (serialiseToRawBytes pid /= serialiseToRawBytes otherPid) $ do + let pat = mkPolicyPattern otherPid + H.assert $ not $ matchesAssetPattern pat val + +hprop_asset_pattern_skips_ada :: Property +hprop_asset_pattern_skips_ada = H.property $ do + pid <- forAll genPolicyId + let val = valueFromList [(AdaAssetId, Quantity 1_000_000)] + pat = mkPolicyPattern pid + H.assert $ not $ matchesAssetPattern pat val + +hprop_asset_pattern_rejects_zero_quantity :: Property +hprop_asset_pattern_rejects_zero_quantity = H.property $ do + pid <- forAll genPolicyId + aname <- forAll genAssetName + let val = valueFromList [(AdaAssetId, Quantity 1_000_000), (AssetId pid aname, Quantity 0)] + pat = mkPolicyPattern pid + H.assert $ not $ matchesAssetPattern pat val + +-- --------------------------------------------------------------------------- +-- E. TxOutputPattern (AND of address + asset) +-- --------------------------------------------------------------------------- + +hprop_tx_output_pattern_requires_both :: Property +hprop_tx_output_pattern_requires_both = H.property $ do + payCred <- forAll genPaymentCredential + nw <- forAll genNetworkId + stakeRef <- forAll genStakeAddressReference + (val, AssetId pid aname) <- forAll genValueWithNativeAsset + + let shelleyAddr = makeShelleyAddress nw payCred stakeRef + addr = shelleyAddressInEra sbe shelleyAddr + meo = MaryEraOnwardsConway + ledgerVal = toLedgerValue meo val + txOutVal = TxOutValueShelleyBased sbe ledgerVal + txOut :: TxOut CtxUTxO ConwayEra + txOut = TxOut addr txOutVal TxOutDatumNone ReferenceScriptNone + addrPat = mkExactAddressPattern addr + assetPat = mkFullAssetPattern pid aname + -- Matching address + matching asset → match + bothPat = mkTxOutputPatternBoth addrPat assetPat + H.assert $ matchesTxOutputPattern bothPat txOut + + -- Matching address + wrong asset → fail + otherPid <- forAll genPolicyId + when (serialiseToRawBytes pid /= serialiseToRawBytes otherPid) $ do + let wrongAssetPat = mkTxOutputPatternBoth addrPat (mkPolicyPattern otherPid) + H.assert $ not $ matchesTxOutputPattern wrongAssetPat txOut + +-- --------------------------------------------------------------------------- +-- F. Boolean combinators (via matchesUtxoPredicate) +-- --------------------------------------------------------------------------- + +hprop_not_inverts_match :: Property +hprop_not_inverts_match = H.property $ do + txOut <- forAll genShelleyTxOut + let inner = wrapInPredicate defMessage -- defMessage matches everything + pred' = defMessage & U5c.not .~ [inner] + -- not [match-everything] should reject everything + H.assert $ not $ matchesUtxoPredicate pred' txOut + +hprop_allOf_conjunction :: Property +hprop_allOf_conjunction = H.property $ do + txOut <- forAll genShelleyTxOut + let p1 = wrapInPredicate defMessage -- matches everything + p2 = wrapInPredicate defMessage -- matches everything + pred' = defMessage & U5c.allOf .~ [p1, p2] + H.assert $ matchesUtxoPredicate pred' txOut + +hprop_anyOf_disjunction :: Property +hprop_anyOf_disjunction = H.property $ do + txOut <- forAll genShelleyTxOut + -- one that matches everything, one with impossible asset + let p1 = wrapInPredicate defMessage + impossibleAsset = mkTxOutputPatternAsset (defMessage & U5c.policyId .~ BS.replicate 28 0xff) + p2 = wrapInPredicate impossibleAsset + pred' = defMessage & U5c.anyOf .~ [p1, p2] + H.assert $ matchesUtxoPredicate pred' txOut + +hprop_anyOf_empty_is_vacuously_true :: Property +hprop_anyOf_empty_is_vacuously_true = H.property $ do + txOut <- forAll genShelleyTxOut + let pred' = defMessage & U5c.anyOf .~ [] + H.assert $ matchesUtxoPredicate pred' txOut + +hprop_match_and_not_combined :: Property +hprop_match_and_not_combined = H.property $ do + txOut <- forAll genShelleyTxOut + -- match=defMessage matches everything, not=[defMessage] negates everything → always fails + let inner = wrapInPredicate defMessage + pred' = + defMessage + & U5c.match .~ (defMessage & U5c.cardano .~ defMessage) + & U5c.not .~ [inner] + H.assert $ not $ matchesUtxoPredicate pred' txOut + +hprop_nested_allOf_anyOf :: Property +hprop_nested_allOf_anyOf = H.property $ do + txOut <- forAll genShelleyTxOut + -- allOf [match-everything, anyOf [match-everything, impossible]] + let pMatch = wrapInPredicate defMessage + impossibleAsset = mkTxOutputPatternAsset (defMessage & U5c.policyId .~ BS.replicate 28 0xff) + pImpossible = wrapInPredicate impossibleAsset + anyPred = defMessage & U5c.anyOf .~ [pMatch, pImpossible] + pred' = defMessage & U5c.allOf .~ [pMatch, anyPred] + H.assert $ matchesUtxoPredicate pred' txOut + +-- --------------------------------------------------------------------------- +-- G. extractAddressesFromPredicate +-- --------------------------------------------------------------------------- + +hprop_extract_simple_exact_address :: Property +hprop_extract_simple_exact_address = H.property $ do + addr <- forAll genAddressShelley + let addrBytes = serialiseToRawBytes addr + pat :: U5c.TxOutputPattern + pat = mkTxOutputPatternAddr (defMessage & U5c.exactAddress .~ addrBytes) + pred' = wrapInPredicate pat + case extractAddressesFromPredicate pred' of + Nothing -> H.failure + Just addrs -> do + H.annotate $ "Extracted: " <> show addrs + Set.size addrs === 1 + +hprop_extract_nothing_for_complex_predicates :: Property +hprop_extract_nothing_for_complex_predicates = H.property $ do + addr <- forAll genAddressShelley + let addrBytes = serialiseToRawBytes addr + pat = mkTxOutputPatternAddr (defMessage & U5c.exactAddress .~ addrBytes) + inner = wrapInPredicate pat + -- Predicate with not → should be Nothing + pred' = defMessage & U5c.not .~ [inner] + extractAddressesFromPredicate pred' === Nothing + +hprop_extract_nothing_for_non_exact_pattern :: Property +hprop_extract_nothing_for_non_exact_pattern = H.property $ do + cred <- forAll genPaymentCredential + let pat = mkTxOutputPatternAddr (mkPaymentPattern cred) + pred' = wrapInPredicate pat + extractAddressesFromPredicate pred' === Nothing + +hprop_extract_anyOf_unions_addresses :: Property +hprop_extract_anyOf_unions_addresses = H.property $ do + addr1 <- forAll genAddressShelley + addr2 <- forAll genAddressShelley + let mkPred a = + let addrBytes = serialiseToRawBytes a + pat = mkTxOutputPatternAddr (defMessage & U5c.exactAddress .~ addrBytes) + in wrapInPredicate pat + pred' = defMessage & U5c.anyOf .~ [mkPred addr1, mkPred addr2] + case extractAddressesFromPredicate pred' of + Nothing -> H.failure + Just addrs -> do + H.annotate $ "Extracted: " <> show addrs + -- Should contain at least 1, at most 2 (might be same address) + H.assert $ Set.size addrs >= 1 && Set.size addrs <= 2 + +hprop_extract_consistent_with_matches :: Property +hprop_extract_consistent_with_matches = H.property $ do + -- If we can extract addresses, then each should match the predicate + addr <- forAll genAddressShelley + let addrBytes = serialiseToRawBytes addr + pat = mkTxOutputPatternAddr (defMessage & U5c.exactAddress .~ addrBytes) + pred' = wrapInPredicate pat + addrInEra = shelleyAddressInEra sbe addr + case extractAddressesFromPredicate pred' of + Nothing -> H.failure + Just _addrs -> do + -- The extracted address should match via matchesAddressPattern + let addrPat :: U5c.AddressPattern + addrPat = defMessage & U5c.exactAddress .~ addrBytes + H.assert $ matchesAddressPattern addrPat addrInEra