Skip to main content

daml_grpc/data/
filter.rs

1use std::collections::HashMap;
2
3use crate::data::identifier::DamlIdentifier;
4use crate::grpc_protobuf::com::daml::ledger::api::v2::cumulative_filter::IdentifierFilter;
5use crate::grpc_protobuf::com::daml::ledger::api::v2::{
6    CumulativeFilter, EventFormat, Filters, InterfaceFilter, ParticipantAuthorizationTopologyFormat, TemplateFilter,
7    TopologyFormat, TransactionFormat, TransactionShape, UpdateFormat, WildcardFilter,
8};
9
10// ---------------------------------------------------------------------------
11// Filter atoms: wildcard, interface, template
12// ---------------------------------------------------------------------------
13
14/// Match every template. The participant ships every contract event
15/// visible to the requesting parties; pair with
16/// [`DamlEventFormat::filters_by_party`] (or `filters_for_any_party`)
17/// to scope.
18///
19/// `include_created_event_blob` controls whether matching
20/// `CreatedEvent`s carry the opaque blob suitable for forwarding as a
21/// `DisclosedContract` in future submissions.
22#[derive(Debug, Clone, Eq, PartialEq, Default)]
23pub struct DamlWildcardFilter {
24    pub include_created_event_blob: bool,
25}
26
27impl From<DamlWildcardFilter> for WildcardFilter {
28    fn from(f: DamlWildcardFilter) -> Self {
29        Self {
30            include_created_event_blob: f.include_created_event_blob,
31        }
32    }
33}
34
35/// Match contracts that implement a specific interface.
36///
37/// `include_interface_view = true` makes the participant evaluate the
38/// interface's `view` method and attach the result to each matching
39/// `CreatedEvent` as a [`DamlInterfaceView`](crate::data::event::DamlInterfaceView).
40#[derive(Debug, Clone, Eq, PartialEq, Default)]
41pub struct DamlInterfaceFilter {
42    pub interface_id: DamlIdentifier,
43    pub include_interface_view: bool,
44    pub include_created_event_blob: bool,
45}
46
47impl From<DamlInterfaceFilter> for InterfaceFilter {
48    fn from(f: DamlInterfaceFilter) -> Self {
49        Self {
50            interface_id: Some(f.interface_id.into()),
51            include_interface_view: f.include_interface_view,
52            include_created_event_blob: f.include_created_event_blob,
53        }
54    }
55}
56
57/// Match contracts of a specific template.
58#[derive(Debug, Clone, Eq, PartialEq, Default)]
59pub struct DamlTemplateFilter {
60    pub template_id: DamlIdentifier,
61    pub include_created_event_blob: bool,
62}
63
64impl From<DamlTemplateFilter> for TemplateFilter {
65    fn from(f: DamlTemplateFilter) -> Self {
66        Self {
67            template_id: Some(f.template_id.into()),
68            include_created_event_blob: f.include_created_event_blob,
69        }
70    }
71}
72
73/// One atom in a [`DamlFilters`] cumulative list.
74///
75/// The proto wraps this as a `oneof identifier_filter` — exactly one
76/// of the three variants is set. Multiple `DamlCumulativeFilter`s in a
77/// `DamlFilters` are OR-ed: a contract event matches if *any* atom
78/// matches.
79#[derive(Debug, Clone, Eq, PartialEq)]
80pub enum DamlCumulativeFilter {
81    Wildcard(DamlWildcardFilter),
82    Interface(DamlInterfaceFilter),
83    Template(DamlTemplateFilter),
84}
85
86impl From<DamlCumulativeFilter> for CumulativeFilter {
87    fn from(f: DamlCumulativeFilter) -> Self {
88        Self {
89            identifier_filter: Some(match f {
90                DamlCumulativeFilter::Wildcard(w) => IdentifierFilter::WildcardFilter(w.into()),
91                DamlCumulativeFilter::Interface(i) => IdentifierFilter::InterfaceFilter(i.into()),
92                DamlCumulativeFilter::Template(t) => IdentifierFilter::TemplateFilter(t.into()),
93            }),
94        }
95    }
96}
97
98// ---------------------------------------------------------------------------
99// Filters: the union/cumulative envelope
100// ---------------------------------------------------------------------------
101
102/// A union of [`DamlCumulativeFilter`]s. An event matches the
103/// `DamlFilters` if *any* of the cumulative atoms matches; per-atom
104/// `include_*` flags are OR-ed on hits.
105///
106/// An empty filter list defaults to a single wildcard with
107/// `include_created_event_blob = false`.
108#[derive(Debug, Clone, Eq, PartialEq, Default)]
109pub struct DamlFilters {
110    pub cumulative: Vec<DamlCumulativeFilter>,
111}
112
113impl DamlFilters {
114    /// Convenience: a single wildcard filter without created-event blobs.
115    pub fn wildcard() -> Self {
116        Self {
117            cumulative: vec![DamlCumulativeFilter::Wildcard(DamlWildcardFilter::default())],
118        }
119    }
120}
121
122impl From<DamlFilters> for Filters {
123    fn from(f: DamlFilters) -> Self {
124        Self {
125            cumulative: f.cumulative.into_iter().map(Into::into).collect(),
126        }
127    }
128}
129
130// ---------------------------------------------------------------------------
131// EventFormat + TransactionShape + TransactionFormat
132// ---------------------------------------------------------------------------
133
134/// Selects whether transaction events are emitted in ACS-delta shape
135/// (`Created` + `Archived`) or ledger-effects shape (`Created` +
136/// `Exercised`, with full subtree information).
137///
138/// The proto also has an `Unspecified = 0` value which it explicitly
139/// documents as "not intended for actual use" — omitted from this
140/// enum.
141#[derive(Debug, Clone, Copy, Eq, PartialEq)]
142pub enum DamlTransactionShape {
143    AcsDelta,
144    LedgerEffects,
145}
146
147impl From<DamlTransactionShape> for TransactionShape {
148    fn from(s: DamlTransactionShape) -> Self {
149        match s {
150            DamlTransactionShape::AcsDelta => TransactionShape::AcsDelta,
151            DamlTransactionShape::LedgerEffects => TransactionShape::LedgerEffects,
152        }
153    }
154}
155
156/// What events to include in an update / ACS / completion stream and
157/// what auxiliary data to compute for them.
158///
159/// `filters_by_party` is keyed by party-id; the value is the filter
160/// that applies when that party witnesses an event.
161/// `filters_for_any_party` is OR-ed with the per-party filters and
162/// applies regardless of party (use it for "I want every event of this
163/// shape" queries).
164///
165/// `verbose = true` makes the participant include human-readable
166/// record-field labels in returned values (useful for debugging, more
167/// bytes on the wire).
168#[derive(Debug, Clone, Eq, PartialEq, Default)]
169pub struct DamlEventFormat {
170    pub filters_by_party: HashMap<String, DamlFilters>,
171    pub filters_for_any_party: Option<DamlFilters>,
172    pub verbose: bool,
173}
174
175impl From<DamlEventFormat> for EventFormat {
176    fn from(f: DamlEventFormat) -> Self {
177        Self {
178            filters_by_party: f.filters_by_party.into_iter().map(|(k, v)| (k, v.into())).collect(),
179            filters_for_any_party: f.filters_for_any_party.map(Into::into),
180            verbose: f.verbose,
181        }
182    }
183}
184
185/// Pairs a [`DamlEventFormat`] with a [`DamlTransactionShape`] —
186/// required wherever the participant streams transactions (e.g.
187/// `UpdateService.GetUpdates`,
188/// `CommandService.SubmitAndWaitForTransaction`).
189#[derive(Debug, Clone, Eq, PartialEq)]
190pub struct DamlTransactionFormat {
191    pub event_format: DamlEventFormat,
192    pub transaction_shape: DamlTransactionShape,
193}
194
195impl From<DamlTransactionFormat> for TransactionFormat {
196    fn from(f: DamlTransactionFormat) -> Self {
197        Self {
198            event_format: Some(f.event_format.into()),
199            transaction_shape: TransactionShape::from(f.transaction_shape) as i32,
200        }
201    }
202}
203
204// ---------------------------------------------------------------------------
205// Topology format
206// ---------------------------------------------------------------------------
207
208/// Filter for participant-authorization topology events.
209/// An empty `parties` list means "every party".
210#[derive(Debug, Clone, Eq, PartialEq, Default)]
211pub struct DamlParticipantAuthorizationTopologyFormat {
212    pub parties: Vec<String>,
213}
214
215impl From<DamlParticipantAuthorizationTopologyFormat> for ParticipantAuthorizationTopologyFormat {
216    fn from(f: DamlParticipantAuthorizationTopologyFormat) -> Self {
217        Self {
218            parties: f.parties,
219        }
220    }
221}
222
223/// Filter for the topology-events portion of an [`DamlUpdateFormat`].
224/// Leave `include_participant_authorization_events = None` to omit
225/// topology events from the stream entirely.
226#[derive(Debug, Clone, Eq, PartialEq, Default)]
227pub struct DamlTopologyFormat {
228    pub include_participant_authorization_events: Option<DamlParticipantAuthorizationTopologyFormat>,
229}
230
231impl From<DamlTopologyFormat> for TopologyFormat {
232    fn from(f: DamlTopologyFormat) -> Self {
233        Self {
234            include_participant_authorization_events: f.include_participant_authorization_events.map(Into::into),
235        }
236    }
237}
238
239// ---------------------------------------------------------------------------
240// UpdateFormat: top-level multiplexer for the update stream
241// ---------------------------------------------------------------------------
242
243/// What kinds of updates a subscription should receive. Each kind is
244/// independently opt-in: leave any field as `None` to omit that kind
245/// of update entirely.
246///
247/// - `include_transactions` — Daml transactions (with their event
248///   shape selected by the inner `DamlTransactionFormat`).
249/// - `include_reassignments` — cross-synchronizer (un)assignments.
250///   Always emitted in ACS-delta shape regardless of the
251///   `DamlEventFormat`'s shape settings.
252/// - `include_topology_events` — participant-authorization topology
253///   transactions.
254#[derive(Debug, Clone, Eq, PartialEq, Default)]
255pub struct DamlUpdateFormat {
256    pub include_transactions: Option<DamlTransactionFormat>,
257    pub include_reassignments: Option<DamlEventFormat>,
258    pub include_topology_events: Option<DamlTopologyFormat>,
259}
260
261impl From<DamlUpdateFormat> for UpdateFormat {
262    fn from(f: DamlUpdateFormat) -> Self {
263        Self {
264            include_transactions: f.include_transactions.map(Into::into),
265            include_reassignments: f.include_reassignments.map(Into::into),
266            include_topology_events: f.include_topology_events.map(Into::into),
267        }
268    }
269}