Skip to content

Commit 1cfbf88

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 c53d6d7 commit 1cfbf88

19 files changed

Lines changed: 644 additions & 296 deletions

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ pub type Result<T> = std::result::Result<T, Error>;
149149
/// Most callers should use the scoped per-endpoint mask types in
150150
/// [`read_mask_fields`](crate::read_mask_fields)
151151
/// (e.g. [`ObjectReadMask`](crate::read_mask_fields::ObjectReadMask)) which
152-
/// are passed directly to the client methods. This type is the underlying
153-
/// string holder, useful when composing masks by hand:
152+
/// are passed directly to the masked client methods. This type is the
153+
/// underlying string holder, useful when composing masks by hand:
154154
///
155155
/// ```
156156
/// 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
@@ -33,17 +33,19 @@ impl Client {
3333
/// - `result.balance_changes()` - Get balance changes (if requested)
3434
/// - `result.object_changes()` - Get object changes (if requested)
3535
///
36-
/// The `read_mask` controls which fields the server returns; use
37-
/// `TransactionReadMask::default()` for the default mask. Pass a
38-
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
39-
/// or any slice/array/vec of fields — conversion is automatic.
36+
/// Uses the default field mask `TransactionReadMask::default()` which
37+
/// includes effects, events, and input/output objects. Use
38+
/// [`execute_transaction_masked`](Self::execute_transaction_masked) to
39+
/// specify a custom mask.
4040
///
4141
/// # Checkpoint Inclusion
4242
///
4343
/// If `checkpoint_inclusion_timeout_ms` is set, the server will wait up to
4444
/// the specified duration (in milliseconds) for the transaction to be
45-
/// included in a checkpoint before returning. When set, include
46-
/// `checkpoint` and `timestamp` in the `read_mask` to receive the data.
45+
/// included in a checkpoint before returning. When set, callers wanting
46+
/// the checkpoint metadata should use
47+
/// [`execute_transaction_masked`](Self::execute_transaction_masked) with a
48+
/// mask that includes `checkpoint` and `timestamp`.
4749
///
4850
/// # Example
4951
///
@@ -55,9 +57,7 @@ impl Client {
5557
/// let client = Client::new_localnet()?;
5658
///
5759
/// let signed_tx: SignedTransaction = todo!();
58-
/// let result = client
59-
/// .execute_transaction(signed_tx, None, TransactionReadMask::default())
60-
/// .await?;
60+
/// let result = client.execute_transaction(signed_tx, None).await?;
6161
///
6262
/// let effects = result.body().effects()?.effects()?;
6363
/// println!("Status: {:?}", effects.as_v1().status);
@@ -73,12 +73,32 @@ impl Client {
7373
&self,
7474
signed_transaction: SignedTransaction,
7575
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
76+
) -> Result<MetadataEnvelope<ExecutedTransaction>> {
77+
self.execute_transactions_internal(
78+
vec![signed_transaction],
79+
checkpoint_inclusion_timeout_ms.into(),
80+
Default::default(),
81+
)
82+
.await?
83+
.try_map(extract_single_execution_result)
84+
}
85+
86+
/// Execute a signed transaction, with a custom read mask.
87+
///
88+
/// See [`execute_transaction`](Self::execute_transaction) for behavior.
89+
/// Pass a
90+
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
91+
/// or any slice/array/vec of fields — conversion is automatic.
92+
pub async fn execute_transaction_masked(
93+
&self,
94+
signed_transaction: SignedTransaction,
95+
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
7696
read_mask: impl IntoReadMask<TransactionReadMask>,
7797
) -> Result<MetadataEnvelope<ExecutedTransaction>> {
78-
self.execute_transactions(
98+
self.execute_transactions_internal(
7999
vec![signed_transaction],
80-
checkpoint_inclusion_timeout_ms,
81-
read_mask,
100+
checkpoint_inclusion_timeout_ms.into(),
101+
read_mask.into_read_mask(),
82102
)
83103
.await?
84104
.try_map(extract_single_execution_result)
@@ -93,18 +113,18 @@ impl Client {
93113
/// input. Each element is either the successfully executed transaction or
94114
/// the per-item error returned by the server.
95115
///
96-
/// The `read_mask` controls which fields the server returns for each
97-
/// `ExecutedTransaction`; use `TransactionReadMask::default()` for the
98-
/// default mask. Pass a
99-
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
100-
/// or any slice/array/vec of fields — conversion is automatic.
116+
/// Uses the default field mask `TransactionReadMask::default()`. Use
117+
/// [`execute_transactions_masked`](Self::execute_transactions_masked) to
118+
/// specify a custom mask.
101119
///
102120
/// # Checkpoint Inclusion
103121
///
104122
/// If `checkpoint_inclusion_timeout_ms` is set, the server will wait up to
105123
/// the specified duration (in milliseconds) for all executed transactions
106-
/// to be included in a checkpoint before returning. When set, include
107-
/// `checkpoint` and `timestamp` in the `read_mask` to receive the data.
124+
/// to be included in a checkpoint before returning. Callers wanting the
125+
/// checkpoint metadata should use
126+
/// [`execute_transactions_masked`](Self::execute_transactions_masked) with
127+
/// a mask that includes `checkpoint` and `timestamp`.
108128
///
109129
/// # Errors
110130
///
@@ -115,10 +135,41 @@ impl Client {
115135
&self,
116136
transactions: Vec<SignedTransaction>,
117137
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
138+
) -> Result<MetadataEnvelope<Vec<Result<ExecutedTransaction>>>> {
139+
self.execute_transactions_internal(
140+
transactions,
141+
checkpoint_inclusion_timeout_ms.into(),
142+
Default::default(),
143+
)
144+
.await
145+
}
146+
147+
/// Execute a batch of signed transactions, with a custom read mask.
148+
///
149+
/// See [`execute_transactions`](Self::execute_transactions) for behavior.
150+
/// Pass a
151+
/// [`TransactionField`](iota_grpc_types::read_mask_fields::TransactionField)
152+
/// or any slice/array/vec of fields — conversion is automatic.
153+
pub async fn execute_transactions_masked(
154+
&self,
155+
transactions: Vec<SignedTransaction>,
156+
checkpoint_inclusion_timeout_ms: impl Into<Option<u64>>,
118157
read_mask: impl IntoReadMask<TransactionReadMask>,
119158
) -> Result<MetadataEnvelope<Vec<Result<ExecutedTransaction>>>> {
120-
let read_mask = read_mask.into_read_mask();
121-
let checkpoint_inclusion_timeout_ms = checkpoint_inclusion_timeout_ms.into();
159+
self.execute_transactions_internal(
160+
transactions,
161+
checkpoint_inclusion_timeout_ms.into(),
162+
read_mask.into_read_mask(),
163+
)
164+
.await
165+
}
166+
167+
async fn execute_transactions_internal(
168+
&self,
169+
transactions: Vec<SignedTransaction>,
170+
checkpoint_inclusion_timeout_ms: Option<u64>,
171+
read_mask: TransactionReadMask,
172+
) -> Result<MetadataEnvelope<Vec<Result<ExecutedTransaction>>>> {
122173
if transactions.is_empty() {
123174
return Err(Error::EmptyRequest);
124175
}

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

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ impl Client {
3232
/// This allows you to preview the effects of a transaction before
3333
/// actually submitting it to the network.
3434
///
35+
/// Uses the default field mask `SimulateReadMask::default()` which includes
36+
/// effects, events, and input/output objects. Use
37+
/// [`simulate_transaction_masked`](Self::simulate_transaction_masked) to
38+
/// specify a custom mask.
39+
///
3540
/// # Parameters
3641
///
3742
/// - `transaction`: The transaction to simulate
@@ -65,9 +70,7 @@ impl Client {
6570
/// let client = Client::new_localnet()?;
6671
///
6772
/// let tx: Transaction = todo!();
68-
/// let result = client
69-
/// .simulate_transaction(tx, false, SimulateReadMask::default())
70-
/// .await?;
73+
/// let result = client.simulate_transaction(tx, false).await?;
7174
///
7275
/// let executed_tx = result.body().executed_transaction()?;
7376
/// let effects = executed_tx.effects()?.effects()?;
@@ -78,23 +81,40 @@ impl Client {
7881
/// # Ok(())
7982
/// # }
8083
/// ```
84+
pub async fn simulate_transaction(
85+
&self,
86+
transaction: Transaction,
87+
skip_checks: bool,
88+
) -> Result<MetadataEnvelope<SimulatedTransaction>> {
89+
self.simulate_transactions_internal(
90+
vec![SimulateTransactionInput {
91+
transaction,
92+
skip_checks,
93+
}],
94+
Default::default(),
95+
)
96+
.await?
97+
.try_map(extract_single_simulation_result)
98+
}
99+
100+
/// Simulate a transaction without executing it, with a custom read mask.
81101
///
82-
/// The `read_mask` controls which fields the server returns; use
83-
/// `SimulateReadMask::default()` for the default mask. Pass a
102+
/// See [`simulate_transaction`](Self::simulate_transaction) for behavior.
103+
/// Pass a
84104
/// [`SimulateField`](iota_grpc_types::read_mask_fields::SimulateField) or
85105
/// any slice/array/vec of fields — conversion is automatic.
86-
pub async fn simulate_transaction(
106+
pub async fn simulate_transaction_masked(
87107
&self,
88108
transaction: Transaction,
89109
skip_checks: bool,
90110
read_mask: impl IntoReadMask<SimulateReadMask>,
91111
) -> Result<MetadataEnvelope<SimulatedTransaction>> {
92-
self.simulate_transactions(
112+
self.simulate_transactions_internal(
93113
vec![SimulateTransactionInput {
94114
transaction,
95115
skip_checks,
96116
}],
97-
read_mask,
117+
read_mask.into_read_mask(),
98118
)
99119
.await?
100120
.try_map(extract_single_simulation_result)
@@ -109,11 +129,9 @@ impl Client {
109129
/// input. Each element is either the successfully simulated transaction or
110130
/// the per-item error returned by the server.
111131
///
112-
/// The `read_mask` controls which fields the server returns for each
113-
/// `SimulatedTransaction`; use `SimulateReadMask::default()` for the
114-
/// default mask. Pass a
115-
/// [`SimulateField`](iota_grpc_types::read_mask_fields::SimulateField) or
116-
/// any slice/array/vec of fields — conversion is automatic.
132+
/// Uses the default field mask `SimulateReadMask::default()`. Use
133+
/// [`simulate_transactions_masked`](Self::simulate_transactions_masked) to
134+
/// specify a custom mask.
117135
///
118136
/// # Errors
119137
///
@@ -123,9 +141,31 @@ impl Client {
123141
pub async fn simulate_transactions(
124142
&self,
125143
transactions: Vec<SimulateTransactionInput>,
144+
) -> Result<MetadataEnvelope<Vec<Result<SimulatedTransaction>>>> {
145+
self.simulate_transactions_internal(transactions, Default::default())
146+
.await
147+
}
148+
149+
/// Simulate a batch of transactions, with a custom read mask.
150+
///
151+
/// See [`simulate_transactions`](Self::simulate_transactions) for
152+
/// behavior. Pass a
153+
/// [`SimulateField`](iota_grpc_types::read_mask_fields::SimulateField) or
154+
/// any slice/array/vec of fields — conversion is automatic.
155+
pub async fn simulate_transactions_masked(
156+
&self,
157+
transactions: Vec<SimulateTransactionInput>,
126158
read_mask: impl IntoReadMask<SimulateReadMask>,
127159
) -> Result<MetadataEnvelope<Vec<Result<SimulatedTransaction>>>> {
128-
let read_mask = read_mask.into_read_mask();
160+
self.simulate_transactions_internal(transactions, read_mask.into_read_mask())
161+
.await
162+
}
163+
164+
async fn simulate_transactions_internal(
165+
&self,
166+
transactions: Vec<SimulateTransactionInput>,
167+
read_mask: SimulateReadMask,
168+
) -> Result<MetadataEnvelope<Vec<Result<SimulatedTransaction>>>> {
129169
if transactions.is_empty() {
130170
return Err(Error::EmptyRequest);
131171
}

0 commit comments

Comments
 (0)