Skip to content

Commit 8c9dbd4

Browse files
feat(grpc): add dedicated _masked query methods
Splits each gRPC query endpoint into two methods: the plain method uses the endpoint's default read mask, and a new `_masked` variant takes an explicit typed mask (`impl Into<XxxReadMask>`), so a bare field, slice, array, or vec of fields can be passed without wrapping. The default methods drop their read-mask parameter; internal callers use the `_masked` variants where a custom mask is required. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8df15d9 commit 8c9dbd4

19 files changed

Lines changed: 657 additions & 300 deletions

crates/iota-sdk-grpc-client/src/api/common.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ pub type Result<T> = std::result::Result<T, Error>;
194194
/// Most callers should use the scoped per-endpoint mask types in
195195
/// [`read_mask_fields`](crate::read_mask_fields)
196196
/// (e.g. [`ObjectReadMask`](crate::read_mask_fields::ObjectReadMask)) which
197-
/// are passed directly to the client methods. This type is the underlying
198-
/// string holder, useful when composing masks by hand:
197+
/// are passed directly to the masked client methods. This type is the
198+
/// underlying string holder, useful when composing masks by hand:
199199
///
200200
/// ```
201201
/// use iota_sdk_grpc_client::ReadMask;

crates/iota-sdk-grpc-client/src/api/execution/execute.rs

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,19 @@ impl Client {
3535
/// - `result.balance_changes()` - Get balance changes (if requested)
3636
/// - `result.object_changes()` - Get object changes (if requested)
3737
///
38-
/// The `read_mask` controls which fields the server returns; use
39-
/// `TransactionReadMask::default()` for the default mask. Pass a
40-
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
41-
/// or any slice/array/vec of fields — conversion is automatic.
38+
/// Uses the default field mask `TransactionReadMask::default()` which
39+
/// includes effects, events, and input/output objects. Use
40+
/// [`execute_transaction_masked`](Self::execute_transaction_masked) to
41+
/// specify a custom mask.
4242
///
4343
/// # Checkpoint Inclusion
4444
///
4545
/// If `checkpoint_inclusion_timeout_ms` is set, the server will wait up to
4646
/// the specified duration (in milliseconds) for the transaction to be
47-
/// included in a checkpoint before returning. When set, include
48-
/// `checkpoint` and `timestamp` in the `read_mask` to receive the data.
47+
/// included in a checkpoint before returning. When set, callers wanting
48+
/// the checkpoint metadata should use
49+
/// [`execute_transaction_masked`](Self::execute_transaction_masked) with a
50+
/// mask that includes `checkpoint` and `timestamp`.
4951
///
5052
/// # Example
5153
///
@@ -57,9 +59,7 @@ impl Client {
5759
/// let client = Client::new_localnet()?;
5860
///
5961
/// let signed_tx: SignedTransaction = todo!();
60-
/// let result = client
61-
/// .execute_transaction(signed_tx, None, TransactionReadMask::default())
62-
/// .await?;
62+
/// let result = client.execute_transaction(signed_tx, None).await?;
6363
///
6464
/// let effects = result.body().effects()?.effects()?;
6565
/// println!("Status: {:?}", effects.as_v1().status);
@@ -75,12 +75,32 @@ impl Client {
7575
&self,
7676
signed_transaction: SignedTransaction,
7777
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
78+
) -> Result<MetadataEnvelope<ExecutedTransaction>> {
79+
self.execute_transactions_internal(
80+
vec![signed_transaction],
81+
checkpoint_inclusion_timeout_ms.into(),
82+
Default::default(),
83+
)
84+
.await?
85+
.try_map(extract_single_execution_result)
86+
}
87+
88+
/// Execute a signed transaction, with a custom read mask.
89+
///
90+
/// See [`execute_transaction`](Self::execute_transaction) for behavior.
91+
/// Pass a
92+
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
93+
/// or any slice/array/vec of fields — conversion is automatic.
94+
pub async fn execute_transaction_masked(
95+
&self,
96+
signed_transaction: SignedTransaction,
97+
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
7898
read_mask: impl IntoReadMask<TransactionReadMask>,
7999
) -> Result<MetadataEnvelope<ExecutedTransaction>> {
80-
self.execute_transactions(
100+
self.execute_transactions_internal(
81101
vec![signed_transaction],
82-
checkpoint_inclusion_timeout_ms,
83-
read_mask,
102+
checkpoint_inclusion_timeout_ms.into(),
103+
read_mask.into_read_mask(),
84104
)
85105
.await?
86106
.try_map(extract_single_execution_result)
@@ -95,18 +115,18 @@ impl Client {
95115
/// input. Each element is either the successfully executed transaction or
96116
/// the per-item error returned by the server.
97117
///
98-
/// The `read_mask` controls which fields the server returns for each
99-
/// `ExecutedTransaction`; use `TransactionReadMask::default()` for the
100-
/// default mask. Pass a
101-
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
102-
/// or any slice/array/vec of fields — conversion is automatic.
118+
/// Uses the default field mask `TransactionReadMask::default()`. Use
119+
/// [`execute_transactions_masked`](Self::execute_transactions_masked) to
120+
/// specify a custom mask.
103121
///
104122
/// # Checkpoint Inclusion
105123
///
106124
/// If `checkpoint_inclusion_timeout_ms` is set, the server will wait up to
107125
/// the specified duration (in milliseconds) for all executed transactions
108-
/// to be included in a checkpoint before returning. When set, include
109-
/// `checkpoint` and `timestamp` in the `read_mask` to receive the data.
126+
/// to be included in a checkpoint before returning. Callers wanting the
127+
/// checkpoint metadata should use
128+
/// [`execute_transactions_masked`](Self::execute_transactions_masked) with
129+
/// a mask that includes `checkpoint` and `timestamp`.
110130
///
111131
/// # Errors
112132
///
@@ -117,10 +137,41 @@ impl Client {
117137
&self,
118138
transactions: Vec<SignedTransaction>,
119139
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
140+
) -> Result<MetadataEnvelope<Vec<Result<ExecutedTransaction>>>> {
141+
self.execute_transactions_internal(
142+
transactions,
143+
checkpoint_inclusion_timeout_ms.into(),
144+
Default::default(),
145+
)
146+
.await
147+
}
148+
149+
/// Execute a batch of signed transactions, with a custom read mask.
150+
///
151+
/// See [`execute_transactions`](Self::execute_transactions) for behavior.
152+
/// Pass a
153+
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
154+
/// or any slice/array/vec of fields — conversion is automatic.
155+
pub async fn execute_transactions_masked(
156+
&self,
157+
transactions: Vec<SignedTransaction>,
158+
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
120159
read_mask: impl IntoReadMask<TransactionReadMask>,
121160
) -> Result<MetadataEnvelope<Vec<Result<ExecutedTransaction>>>> {
122-
let read_mask = read_mask.into_read_mask();
123-
let checkpoint_inclusion_timeout_ms = checkpoint_inclusion_timeout_ms.into();
161+
self.execute_transactions_internal(
162+
transactions,
163+
checkpoint_inclusion_timeout_ms.into(),
164+
read_mask.into_read_mask(),
165+
)
166+
.await
167+
}
168+
169+
async fn execute_transactions_internal(
170+
&self,
171+
transactions: Vec<SignedTransaction>,
172+
checkpoint_inclusion_timeout_ms: Option<u64>,
173+
read_mask: TransactionReadMask,
174+
) -> Result<MetadataEnvelope<Vec<Result<ExecutedTransaction>>>> {
124175
if transactions.is_empty() {
125176
return Err(Error::EmptyRequest);
126177
}

crates/iota-sdk-grpc-client/src/api/execution/simulate.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ impl Client {
3434
/// This allows you to preview the effects of a transaction before
3535
/// actually submitting it to the network.
3636
///
37+
/// Uses the default field mask `SimulateReadMask::default()` which includes
38+
/// effects, events, and input/output objects. Use
39+
/// [`simulate_transaction_masked`](Self::simulate_transaction_masked) to
40+
/// specify a custom mask.
41+
///
3742
/// # Parameters
3843
///
3944
/// - `transaction`: The transaction to simulate
@@ -67,9 +72,7 @@ impl Client {
6772
/// let client = Client::new_localnet()?;
6873
///
6974
/// let tx: Transaction = todo!();
70-
/// let result = client
71-
/// .simulate_transaction(tx, false, SimulateReadMask::default())
72-
/// .await?;
75+
/// let result = client.simulate_transaction(tx, false).await?;
7376
///
7477
/// let executed_tx = result.body().executed_transaction()?;
7578
/// let effects = executed_tx.effects()?.effects()?;
@@ -80,23 +83,40 @@ impl Client {
8083
/// # Ok(())
8184
/// # }
8285
/// ```
86+
pub async fn simulate_transaction(
87+
&self,
88+
transaction: Transaction,
89+
skip_checks: bool,
90+
) -> Result<MetadataEnvelope<SimulatedTransaction>> {
91+
self.simulate_transactions_internal(
92+
vec![SimulateTransactionInput {
93+
transaction,
94+
skip_checks,
95+
}],
96+
Default::default(),
97+
)
98+
.await?
99+
.try_map(extract_single_simulation_result)
100+
}
101+
102+
/// Simulate a transaction without executing it, with a custom read mask.
83103
///
84-
/// The `read_mask` controls which fields the server returns; use
85-
/// `SimulateReadMask::default()` for the default mask. Pass a
104+
/// See [`simulate_transaction`](Self::simulate_transaction) for behavior.
105+
/// Pass a
86106
/// [`SimulateField`](iota_grpc_types::read_mask_fields::SimulateField) or
87107
/// any slice/array/vec of fields — conversion is automatic.
88-
pub async fn simulate_transaction(
108+
pub async fn simulate_transaction_masked(
89109
&self,
90110
transaction: Transaction,
91111
skip_checks: bool,
92112
read_mask: impl IntoReadMask<SimulateReadMask>,
93113
) -> Result<MetadataEnvelope<SimulatedTransaction>> {
94-
self.simulate_transactions(
114+
self.simulate_transactions_internal(
95115
vec![SimulateTransactionInput {
96116
transaction,
97117
skip_checks,
98118
}],
99-
read_mask,
119+
read_mask.into_read_mask(),
100120
)
101121
.await?
102122
.try_map(extract_single_simulation_result)
@@ -111,11 +131,9 @@ impl Client {
111131
/// input. Each element is either the successfully simulated transaction or
112132
/// the per-item error returned by the server.
113133
///
114-
/// The `read_mask` controls which fields the server returns for each
115-
/// `SimulatedTransaction`; use `SimulateReadMask::default()` for the
116-
/// default mask. Pass a
117-
/// [`SimulateField`](iota_grpc_types::read_mask_fields::SimulateField) or
118-
/// any slice/array/vec of fields — conversion is automatic.
134+
/// Uses the default field mask `SimulateReadMask::default()`. Use
135+
/// [`simulate_transactions_masked`](Self::simulate_transactions_masked) to
136+
/// specify a custom mask.
119137
///
120138
/// # Errors
121139
///
@@ -125,9 +143,31 @@ impl Client {
125143
pub async fn simulate_transactions(
126144
&self,
127145
transactions: Vec<SimulateTransactionInput>,
146+
) -> Result<MetadataEnvelope<Vec<Result<SimulatedTransaction>>>> {
147+
self.simulate_transactions_internal(transactions, Default::default())
148+
.await
149+
}
150+
151+
/// Simulate a batch of transactions, with a custom read mask.
152+
///
153+
/// See [`simulate_transactions`](Self::simulate_transactions) for
154+
/// behavior. Pass a
155+
/// [`SimulateField`](iota_grpc_types::read_mask_fields::SimulateField) or
156+
/// any slice/array/vec of fields — conversion is automatic.
157+
pub async fn simulate_transactions_masked(
158+
&self,
159+
transactions: Vec<SimulateTransactionInput>,
128160
read_mask: impl IntoReadMask<SimulateReadMask>,
129161
) -> Result<MetadataEnvelope<Vec<Result<SimulatedTransaction>>>> {
130-
let read_mask = read_mask.into_read_mask();
162+
self.simulate_transactions_internal(transactions, read_mask.into_read_mask())
163+
.await
164+
}
165+
166+
async fn simulate_transactions_internal(
167+
&self,
168+
transactions: Vec<SimulateTransactionInput>,
169+
read_mask: SimulateReadMask,
170+
) -> Result<MetadataEnvelope<Vec<Result<SimulatedTransaction>>>> {
131171
if transactions.is_empty() {
132172
return Err(Error::EmptyRequest);
133173
}

0 commit comments

Comments
 (0)