penumbra_sdk_transaction/
gas.rs

1use penumbra_sdk_auction::auction::dutch::actions::{
2    ActionDutchAuctionEnd, ActionDutchAuctionSchedule, ActionDutchAuctionWithdraw,
3};
4use penumbra_sdk_community_pool::{CommunityPoolDeposit, CommunityPoolOutput, CommunityPoolSpend};
5use penumbra_sdk_dex::{PositionClose, PositionOpen, PositionWithdraw, Swap, SwapClaim};
6use penumbra_sdk_fee::Gas;
7use penumbra_sdk_ibc::IbcRelay;
8use penumbra_sdk_shielded_pool::{Ics20Withdrawal, Output, Spend};
9use penumbra_sdk_stake::{
10    validator::Definition as ValidatorDefinition, Delegate, Undelegate, UndelegateClaim,
11};
12
13use penumbra_sdk_governance::{
14    DelegatorVote, ProposalDepositClaim, ProposalSubmit, ProposalWithdraw, ValidatorVote,
15};
16
17use crate::{
18    plan::{ActionPlan, TransactionPlan},
19    Action, Transaction,
20};
21
22use penumbra_sdk_proto::DomainType;
23
24const NULLIFIER_SIZE: u64 = 2 + 32;
25const NOTEPAYLOAD_SIZE: u64 = 32 + 32 + 176;
26const SWAPPAYLOAD_SIZE: u64 = 32 + 272;
27const ZKPROOF_SIZE: u64 = 192;
28// This is an approximation, the actual size is variable
29const BSOD_SIZE: u64 = 16 + 16 + 0 + 4 + 64 + 4;
30
31/// Allows [`Action`]s and [`Transaction`]s to statically indicate their relative resource consumption.
32/// Since the gas cost needs to be multiplied by a price, the values returned
33/// only need to be scaled relatively to each other.
34pub trait GasCost {
35    fn gas_cost(&self) -> Gas;
36}
37
38// Where block space costs are hard-coded instead of calculated in the following functions, the values are based on the approximate byte size of the
39// encoded action and ignore the protobuf framing overhead, because it makes only a small difference and simplifies accounting.
40
41pub fn spend_gas_cost() -> Gas {
42    Gas {
43        // penumbra.core.asset.v1.BalanceCommitment `balance_commitment`  = 32 bytes
44        // penumbra.core.component.sct.v1.Nullifier `nullifier`           = 32 bytes
45        // penumbra.crypto.decaf377_rdsa.v1.SpendVerificationKey `rk`     = 32 bytes
46        // penumbra.crypto.decaf377_rdsa.v1.SpendAuthSignature `auth_sig` = 64 bytes
47        // ZKSpendProof `proof`                                           = 192 bytes
48
49        // The block space measured as the byte length of the encoded action.
50        block_space: 160 + ZKPROOF_SIZE, // 352 bytes
51        // The compact block space cost is based on the byte size of the data the [`Action`] adds
52        // to the compact block. For a `Spend`, this is the byte size of a `Nullifier`.
53        compact_block_space: NULLIFIER_SIZE,
54        // Includes a zk-SNARK proof, so we include a constant verification cost.
55        verification: 1000,
56        // Execution cost is currently hardcoded at 10 for all [`Action`] variants.
57        execution: 10,
58    }
59}
60
61pub fn output_gas_cost() -> Gas {
62    Gas {
63        // NotePayload `note_payload` = 32 + 32 + 176                    = 240 bytes
64        // penumbra.core.asset.v1.BalanceCommitment `balance_commitment` = 32 bytes
65        // wrapped_memo_key `wrapped_memo_key`                           = 48 bytes
66        // ovk_wrapped_key `ovk_wrapped_key`                             = 48 bytes
67        // ZKOutputProof `proof`                                         = 192 bytes
68
69        // The block space measured as the byte length of the encoded action.
70        block_space: 128 + NOTEPAYLOAD_SIZE + ZKPROOF_SIZE, // 560 bytes
71        // The compact block space cost is based on the byte size of the data the [`Action`] adds
72        // to the compact block.
73        compact_block_space: NOTEPAYLOAD_SIZE,
74        // Includes a zk-SNARK proof, so we include a constant verification cost.
75        verification: 1000,
76        // Execution cost is currently hardcoded at 10 for all [`Action`] variants.
77        execution: 10,
78    }
79}
80
81fn delegate_gas_cost(delegate: &Delegate) -> Gas {
82    Gas {
83        // The block space measured as the byte length of the encoded action.
84        block_space: delegate.encode_to_vec().len() as u64,
85        // The compact block space cost is based on the byte size of the data the [`Action`] adds
86        // to the compact block.
87        // For a Delegate, nothing is added to the compact block directly. The associated [`Action::Spend`]
88        // actions will add their costs, but there's nothing to add here.
89        compact_block_space: 0,
90        // Does not include a zk-SNARK proof, so there's no verification cost.
91        verification: 0,
92        // Execution cost is currently hardcoded at 10 for all Action variants.
93        execution: 10,
94    }
95}
96
97fn undelegate_gas_cost(undelegate: &Undelegate) -> Gas {
98    Gas {
99        // The block space measured as the byte length of the encoded action.
100        block_space: undelegate.encode_to_vec().len() as u64,
101        // The compact block space cost is based on the byte size of the data the [`Action`] adds
102        // to the compact block.
103        // For an Undelegate, nothing is added to the compact block directly. The associated [`Action::Spend`]
104        // actions will add their costs, but there's nothing to add here.
105        compact_block_space: 0,
106        // Does not include a zk-SNARK proof, so there's no verification cost.
107        verification: 0,
108        // Execution cost is currently hardcoded at 10 for all Action variants.
109        execution: 10,
110    }
111}
112
113fn undelegate_claim_gas_cost() -> Gas {
114    Gas {
115        // penumbra.core.keys.v1.IdentityKey `validator_identity`         = 32 bytes
116        // uint64 `start_epoch_index`                                     = 8 bytes
117        // Penalty `penalty`                                              = 32 bytes
118        // penumbra.core.asset.v1.BalanceCommitment `balance_commitment`  = 32 bytes
119        // uint64 `unbonding_start_height`                                = 8 bytes
120        // ZKSpendProof `proof`                                           = 192 bytes
121
122        // The block space measured as the byte length of the encoded action.
123        block_space: 112 + ZKPROOF_SIZE, // 304 bytes
124        // The compact block space cost is based on the byte size of the data the [`Action`] adds
125        // to the compact block.
126        // For an `UndelegateClaim`, nothing is added to the compact block directly. The associated [`Action::Output`]
127        // actions will add their costs, but there's nothing to add here.
128        compact_block_space: 0,
129        // Includes a zk-SNARK proof, so we include a constant verification cost.
130        verification: 1000,
131        // Execution cost is currently hardcoded at 10 for all Action variants.
132        execution: 10,
133    }
134}
135
136fn validator_definition_gas_cost(validator_definition: &ValidatorDefinition) -> Gas {
137    Gas {
138        // The block space measured as the byte length of the encoded action.
139        block_space: validator_definition.encode_to_vec().len() as u64,
140        // The compact block space cost is based on the byte size of the data the [`Action`] adds
141        // to the compact block.
142        // For a ValidatorDefinition the compact block is not modified.
143        compact_block_space: 0,
144        // Includes a signature verification, so we include a small constant verification cost.
145        verification: 200,
146        // Execution cost is currently hardcoded at 10 for all Action variants.
147        execution: 10,
148    }
149}
150
151fn swap_gas_cost() -> Gas {
152    Gas {
153        // TradingPair `trading_pair`                                = 64 bytes
154        // penumbra.core.num.v1.Amount `delta_1_i`                   = 16 bytes
155        // penumbra.core.num.v1.Amount `delta_2_i`                   = 16 bytes
156        // penumbra.core.asset.v1.BalanceCommitment `fee_commitment` = 32 bytes
157        // SwapPayload `payload`                                     = 304 bytes
158        // ZKSwapProof `proof`                                       = 192 bytes
159        // Batch swap output data                                    = 104 bytes
160
161        // The block space measured as the byte length of the encoded action.
162        block_space: 128 + ZKPROOF_SIZE + SWAPPAYLOAD_SIZE + BSOD_SIZE, // 728 bytes
163        // The compact block space cost is based on the byte size of the data the [`Action`] adds
164        // to the compact block.
165        // For a `Swap` this is the byte size of a [`StatePayload`] and a [`BatchSwapOutputData`].
166        // `Swap`s are batched so technically the cost of the `BatchSwapOutputData` is shared across
167        // multiple swaps, but if only one `swap` for a trading pair is performed in a block, that
168        // `swap` will add a `BatchSwapOutputData` all on its own.
169        // Note: the BSOD has variable size, we pick an approximation.
170        compact_block_space: SWAPPAYLOAD_SIZE + BSOD_SIZE,
171        // Includes a zk-SNARK proof, so we include a constant verification cost.
172        verification: 1000,
173        // Execution cost is currently hardcoded at 10 for all Action variants.
174        execution: 10,
175    }
176}
177
178pub fn swap_claim_gas_cost() -> Gas {
179    Gas {
180        // penumbra.core.component.sct.v1.Nullifier `nullifier`           = 32 bytes
181        // penumbra.core.component.fee.v1.Fee `fee``                      = 48 bytes
182        // penumbra.crypto.tct.v1.StateCommitment `output_1_commitment``  = 32 bytes
183        // penumbra.crypto.tct.v1.StateCommitment `output_2_commitment`   = 32 bytes
184        // BatchSwapOutputData `output_data`                              = 176 bytes
185        // uint64 `epoch_duration`                                        = 8 bytes
186        // ZKSwapClaimProof `proof`                                       = 192 bytes
187        // Batch swap output data                                          = 104 bytes
188
189        // The block space measured as the byte length of the encoded action.
190        block_space: 328 + ZKPROOF_SIZE + BSOD_SIZE, // 624 bytes
191        // The compact block space cost is based on the byte size of the data the [`Action`] adds
192        // to the compact block.
193        // For a `SwapClaim`, nothing is added to the compact block directly. The associated [`Action::Spend`]
194        // and [`Action::Output`] actions will add their costs, but there's nothing to add here.
195        compact_block_space: 0,
196        // Includes a zk-SNARK proof, so we include a constant verification cost.
197        verification: 1000,
198        // Execution cost is currently hardcoded at 10 for all Action variants.
199        execution: 10,
200    }
201}
202
203fn delegator_vote_gas_cost() -> Gas {
204    Gas {
205        // uint64 `proposal`                                                = 8 bytes
206        // uint64 `start_position`                                          = 8 bytes
207        // Vote `vote`                                                      = 1 byte
208        // penumbra.core.asset.v1.Value `value`                             = 48 bytes
209        // penumbra.core.num.v1.Amount `unbonded_amount`                    = 16 bytes
210        // penumbra.core.component.sct.v1.Nullifier `nullifier`             = 32 bytes
211        // penumbra.crypto.decaf377_rdsa.v1.SpendVerificationKey `rk`       = 32 bytes
212        // penumbra.crypto.decaf377_rdsa.v1.SpendAuthSignature `auth_sig`   = 64 bytes
213        // ZKDelegatorVoteProof `proof`                                     = 192 bytes
214
215        // The block space measured as the byte length of the encoded action.
216        block_space: 209 + ZKPROOF_SIZE, // 401 bytes
217        // The compact block space cost is based on the byte size of the data the [`Action`] adds
218        // to the compact block.
219        // For a DelegatorVote the compact block is not modified.
220        compact_block_space: 0,
221        // Includes a zk-SNARK proof, so we include a constant verification cost.
222        verification: 1000,
223        // Execution cost is currently hardcoded at 10 for all Action variants.
224        execution: 10,
225    }
226}
227
228fn position_withdraw_gas_cost() -> Gas {
229    Gas {
230        // PositionId `position_id`                                        = 32 bytes
231        // penumbra.core.asset.v1.BalanceCommitment `reserves_commitment`  = 32 bytes
232        // uint64 `sequence`                                               = 8 bytes
233
234        // The block space measured as the byte length of the encoded action.
235        block_space: 72, // 72 bytes
236        // The compact block space cost is based on the byte size of the data the [`Action`] adds
237        // to the compact block.
238        // For a PositionWithdraw the compact block is not modified.
239        compact_block_space: 0,
240        // Does not include a zk-SNARK proof, so there's no verification cost.
241        verification: 0,
242        // Execution cost is currently hardcoded at 10 for all `Action`` variants.
243        // Reminder: Any change to this execution gas vector must also be reflected
244        // in updates to the dutch auction gas vectors.
245        execution: 10,
246    }
247}
248
249fn dutch_auction_schedule_gas_cost(dutch_action_schedule: &ActionDutchAuctionSchedule) -> Gas {
250    Gas {
251        // penumbra.core.asset.v1.Value `input` = 48 bytes
252        // penumbra.core.asset.v1.AssetId `output_id` = 32 bytes
253        // penumbra.core.num.v1.Amount `max_output` = 16 bytes
254        // penumbra.core.num.v1.Amount `min_output` = 16 bytes
255        // uint64 `start_height` = 8 bytes
256        // uint64 `end_height` = 8 bytes
257        // uint64 `step_count` = 8 bytes
258        // bytes `nonce` = 32 bytes
259        block_space: 168,
260        compact_block_space: 0,
261        verification: 50,
262        // Currently, we make the execution cost for DA actions proportional to the number of steps
263        // and costs of position open/close in dutch action. The gas cost is calculated by:
264        // 2 * step_count * (`PositionOpen`` + `PositionClose` cost).
265        execution: 2 * dutch_action_schedule.description.step_count * (10 + 10),
266    }
267}
268
269fn dutch_auction_end_gas_cost() -> Gas {
270    Gas {
271        // AuctionId `auction_id` = 32 bytes
272        block_space: 32, // 32 bytes
273        compact_block_space: 0,
274        verification: 0,
275        execution: 10,
276    }
277}
278
279fn dutch_auction_withdraw_gas_cost() -> Gas {
280    Gas {
281        // AuctionId `auction_id` = 32 bytes
282        // uint64 `seq`= 8 bytes
283        // penumbra.core.asset.v1.BalanceCommitment `reserves_commitment` = 32 bytes
284        block_space: 72, // 72 bytes
285        compact_block_space: 0,
286        verification: 0,
287        execution: 10,
288    }
289}
290
291impl GasCost for Transaction {
292    fn gas_cost(&self) -> Gas {
293        self.actions().map(GasCost::gas_cost).sum()
294    }
295}
296
297impl GasCost for TransactionPlan {
298    fn gas_cost(&self) -> Gas {
299        self.actions.iter().map(GasCost::gas_cost).sum()
300    }
301}
302
303// The planner also needs to be able to calculate gas costs,
304// however until the transaction is finalized, the planner only
305// has access to `ActionPlan` variants.
306//
307// IMPORTANT: The results produced by this impl should always
308// match what the impl for the associated `Action` variant would
309// produce, otherwise the planner will not include proper gas in
310// transactions.
311impl GasCost for ActionPlan {
312    fn gas_cost(&self) -> Gas {
313        match self {
314            // Some variants use separate `*Plan` inners and need their
315            // own implementations; others encapsulate an `Action` variant
316            // and can call the `GasCost` impl on that.
317            ActionPlan::Spend(_) => spend_gas_cost(),
318            ActionPlan::Output(_) => output_gas_cost(),
319            ActionPlan::UndelegateClaim(_) => undelegate_claim_gas_cost(),
320            ActionPlan::Swap(_) => swap_gas_cost(),
321            ActionPlan::SwapClaim(_) => swap_claim_gas_cost(),
322            ActionPlan::DelegatorVote(_) => delegator_vote_gas_cost(),
323            ActionPlan::PositionWithdraw(_) => position_withdraw_gas_cost(),
324            ActionPlan::ActionDutchAuctionSchedule(das) => das.gas_cost(),
325            ActionPlan::ActionDutchAuctionEnd(_) => dutch_auction_end_gas_cost(),
326            ActionPlan::ActionDutchAuctionWithdraw(_) => dutch_auction_withdraw_gas_cost(),
327
328            ActionPlan::Delegate(d) => d.gas_cost(),
329            ActionPlan::Undelegate(u) => u.gas_cost(),
330            ActionPlan::ValidatorDefinition(vd) => vd.gas_cost(),
331            ActionPlan::IbcAction(i) => i.gas_cost(),
332            ActionPlan::ProposalSubmit(ps) => ps.gas_cost(),
333            ActionPlan::ProposalWithdraw(pw) => pw.gas_cost(),
334            ActionPlan::ValidatorVote(v) => v.gas_cost(),
335            ActionPlan::ProposalDepositClaim(pdc) => pdc.gas_cost(),
336            ActionPlan::PositionOpen(po) => po.gas_cost(),
337            ActionPlan::PositionClose(pc) => pc.gas_cost(),
338            ActionPlan::CommunityPoolSpend(ds) => ds.gas_cost(),
339            ActionPlan::CommunityPoolOutput(d) => d.gas_cost(),
340            ActionPlan::CommunityPoolDeposit(dd) => dd.gas_cost(),
341            ActionPlan::Ics20Withdrawal(w) => w.gas_cost(),
342        }
343    }
344}
345
346impl GasCost for Action {
347    fn gas_cost(&self) -> Gas {
348        match self {
349            Action::Output(output) => output.gas_cost(),
350            Action::Spend(spend) => spend.gas_cost(),
351            Action::Delegate(delegate) => delegate.gas_cost(),
352            Action::Undelegate(undelegate) => undelegate.gas_cost(),
353            Action::UndelegateClaim(undelegate_claim) => undelegate_claim.gas_cost(),
354            Action::Swap(swap) => swap.gas_cost(),
355            Action::SwapClaim(swap_claim) => swap_claim.gas_cost(),
356            Action::ProposalSubmit(submit) => submit.gas_cost(),
357            Action::ProposalWithdraw(withdraw) => withdraw.gas_cost(),
358            Action::DelegatorVote(delegator_vote) => delegator_vote.gas_cost(),
359            Action::ValidatorVote(validator_vote) => validator_vote.gas_cost(),
360            Action::ProposalDepositClaim(p) => p.gas_cost(),
361            Action::PositionOpen(p) => p.gas_cost(),
362            Action::PositionClose(p) => p.gas_cost(),
363            Action::PositionWithdraw(p) => p.gas_cost(),
364            Action::Ics20Withdrawal(withdrawal) => withdrawal.gas_cost(),
365            Action::CommunityPoolDeposit(deposit) => deposit.gas_cost(),
366            Action::CommunityPoolSpend(spend) => spend.gas_cost(),
367            Action::CommunityPoolOutput(output) => output.gas_cost(),
368            Action::IbcRelay(x) => x.gas_cost(),
369            Action::ValidatorDefinition(x) => x.gas_cost(),
370            Action::ActionDutchAuctionSchedule(action_dutch_auction_schedule) => {
371                action_dutch_auction_schedule.gas_cost()
372            }
373            Action::ActionDutchAuctionEnd(action_dutch_auction_end) => {
374                action_dutch_auction_end.gas_cost()
375            }
376            Action::ActionDutchAuctionWithdraw(action_dutch_auction_withdraw) => {
377                action_dutch_auction_withdraw.gas_cost()
378            }
379        }
380    }
381}
382
383impl GasCost for Output {
384    fn gas_cost(&self) -> Gas {
385        output_gas_cost()
386    }
387}
388
389impl GasCost for Spend {
390    fn gas_cost(&self) -> Gas {
391        spend_gas_cost()
392    }
393}
394
395impl GasCost for Delegate {
396    fn gas_cost(&self) -> Gas {
397        delegate_gas_cost(&self)
398    }
399}
400
401impl GasCost for Undelegate {
402    fn gas_cost(&self) -> Gas {
403        undelegate_gas_cost(&self)
404    }
405}
406
407impl GasCost for UndelegateClaim {
408    fn gas_cost(&self) -> Gas {
409        undelegate_claim_gas_cost()
410    }
411}
412
413impl GasCost for Swap {
414    fn gas_cost(&self) -> Gas {
415        swap_gas_cost()
416    }
417}
418
419impl GasCost for SwapClaim {
420    fn gas_cost(&self) -> Gas {
421        swap_claim_gas_cost()
422    }
423}
424
425impl GasCost for ProposalSubmit {
426    fn gas_cost(&self) -> Gas {
427        Gas {
428            // The block space measured as the byte length of the encoded action.
429            block_space: self.encode_to_vec().len() as u64,
430            // In the case of a proposal submission, the compact block cost is zero.
431            // The compact block is only modified it the proposal is ratified.
432            // And when that's the case, the cost is mutualized.
433            compact_block_space: 0,
434            // There are some checks performed to validate the proposed state changes, so we include a constant verification cost,
435            // smaller than a zk-SNARK verification cost.
436            verification: 100,
437            // Execution cost is currently hardcoded at 10 for all Action variants.
438            execution: 10,
439        }
440    }
441}
442
443impl GasCost for ProposalWithdraw {
444    fn gas_cost(&self) -> Gas {
445        Gas {
446            // The block space measured as the byte length of the encoded action.
447            block_space: self.encode_to_vec().len() as u64,
448            // The compact block space cost is based on the byte size of the data the [`Action`] adds
449            // to the compact block.
450            // For a ProposalWithdraw the compact block is not modified.
451            compact_block_space: 0,
452            // Does not include a zk-SNARK proof, so there's no verification cost.
453            verification: 0,
454            // Execution cost is currently hardcoded at 10 for all Action variants.
455            execution: 10,
456        }
457    }
458}
459
460impl GasCost for DelegatorVote {
461    fn gas_cost(&self) -> Gas {
462        delegator_vote_gas_cost()
463    }
464}
465
466impl GasCost for ValidatorVote {
467    fn gas_cost(&self) -> Gas {
468        Gas {
469            // The block space measured as the byte length of the encoded action.
470            block_space: self.encode_to_vec().len() as u64,
471            // The compact block space cost is based on the byte size of the data the [`Action`] adds
472            // to the compact block.
473            // For a ValidatorVote the compact block is not modified.
474            compact_block_space: 0,
475            // Includes a signature verification, so we include a small constant verification cost.
476            verification: 200,
477            // Execution cost is currently hardcoded at 10 for all Action variants.
478            execution: 10,
479        }
480    }
481}
482
483impl GasCost for ProposalDepositClaim {
484    fn gas_cost(&self) -> Gas {
485        Gas {
486            // The block space measured as the byte length of the encoded action.
487            block_space: self.encode_to_vec().len() as u64,
488            // The compact block space cost is based on the byte size of the data the [`Action`] adds
489            // to the compact block.
490            // For a ProposalDepositClaim the compact block is not modified.
491            compact_block_space: 0,
492            // Does not include a zk-SNARK proof, so there's no verification cost.
493            verification: 0,
494            // Execution cost is currently hardcoded at 10 for all Action variants.
495            execution: 10,
496        }
497    }
498}
499
500impl GasCost for PositionOpen {
501    fn gas_cost(&self) -> Gas {
502        Gas {
503            // The block space measured as the byte length of the encoded action.
504            block_space: self.encode_to_vec().len() as u64,
505            // The compact block space cost is based on the byte size of the data the [`Action`] adds
506            // to the compact block.
507            // For a PositionOpen the compact block is not modified.
508            compact_block_space: 0,
509            // There are some small validations performed so a token amount of gas is charged.
510            verification: 50,
511            // Execution cost is currently hardcoded at 10 for all Action variants.
512            // Reminder: Any change to this execution gas vector must also be reflected
513            // in updates to the dutch auction gas vectors.
514            execution: 10,
515        }
516    }
517}
518
519impl GasCost for PositionClose {
520    fn gas_cost(&self) -> Gas {
521        Gas {
522            // The block space measured as the byte length of the encoded action.
523            block_space: self.encode_to_vec().len() as u64,
524            // The compact block space cost is based on the byte size of the data the [`Action`] adds
525            // to the compact block.
526            // For a PositionClose the compact block is not modified.
527            compact_block_space: 0,
528            // Does not include a zk-SNARK proof, so there's no verification cost.
529            verification: 0,
530            // Execution cost is currently hardcoded at 10 for all Action variants.
531            // Reminder: Any change to this execution gas vector must also be reflected
532            // in updates to the dutch auction gas vectors.
533            execution: 10,
534        }
535    }
536}
537
538impl GasCost for PositionWithdraw {
539    fn gas_cost(&self) -> Gas {
540        position_withdraw_gas_cost()
541    }
542}
543
544impl GasCost for Ics20Withdrawal {
545    fn gas_cost(&self) -> Gas {
546        Gas {
547            // The block space measured as the byte length of the encoded action.
548            block_space: self.encode_to_vec().len() as u64,
549            // The compact block space cost is based on the byte size of the data the [`Action`] adds
550            // to the compact block.
551            // For a Ics20Withdrawal the compact block is not modified.
552            compact_block_space: 0,
553            // Does not include a zk-SNARK proof, so there's no verification cost.
554            verification: 0,
555            // Execution cost is currently hardcoded at 10 for all Action variants.
556            execution: 10,
557        }
558    }
559}
560
561impl GasCost for CommunityPoolDeposit {
562    fn gas_cost(&self) -> Gas {
563        Gas {
564            // The block space measured as the byte length of the encoded action.
565            block_space: self.encode_to_vec().len() as u64,
566            // The compact block space cost is based on the byte size of the data the [`Action`] adds
567            // to the compact block.
568            // For a CommunityPoolDeposit the compact block is not modified.
569            compact_block_space: 0,
570            // Does not include a zk-SNARK proof, so there's no verification cost.
571            verification: 0,
572            // Execution cost is currently hardcoded at 10 for all Action variants.
573            execution: 10,
574        }
575    }
576}
577
578impl GasCost for CommunityPoolSpend {
579    fn gas_cost(&self) -> Gas {
580        Gas {
581            // The block space measured as the byte length of the encoded action.
582            block_space: self.encode_to_vec().len() as u64,
583            // The compact block space cost is based on the byte size of the data the [`Action`] adds
584            // to the compact block.
585            // For a CommunityPoolSpend the compact block is not modified.
586            compact_block_space: 0,
587            // Does not include a zk-SNARK proof, so there's no verification cost.
588            verification: 0,
589            // Execution cost is currently hardcoded at 10 for all Action variants.
590            execution: 10,
591        }
592    }
593}
594
595impl GasCost for CommunityPoolOutput {
596    fn gas_cost(&self) -> Gas {
597        // We hardcode the gas costs of a `CommunityPoolOutput` to 0, since it's a protocol action.
598        Gas {
599            block_space: 0,
600            compact_block_space: 0,
601            verification: 0,
602            execution: 0,
603        }
604    }
605}
606
607impl GasCost for IbcRelay {
608    fn gas_cost(&self) -> Gas {
609        Gas {
610            // The block space measured as the byte length of the encoded action.
611            block_space: self.encode_to_vec().len() as u64,
612            // The compact block space cost is based on the byte size of the data the [`Action`] adds
613            // to the compact block.
614            // For a IbcAction this is the byte size of a [`StatePayload`].
615            compact_block_space: match self {
616                // RecvPacket will mint a note if successful.
617                IbcRelay::RecvPacket(_) => NOTEPAYLOAD_SIZE,
618                _ => 0,
619            },
620            // Includes a proof in the execution for RecvPacket (TODO: check the other variants).
621            verification: match self {
622                IbcRelay::RecvPacket(_) => 1000,
623                _ => 0,
624            },
625            // Execution cost is currently hardcoded at 10 for all Action variants.
626            execution: 10,
627        }
628    }
629}
630
631impl GasCost for ValidatorDefinition {
632    fn gas_cost(&self) -> Gas {
633        validator_definition_gas_cost(&self)
634    }
635}
636
637impl GasCost for ActionDutchAuctionSchedule {
638    fn gas_cost(&self) -> Gas {
639        dutch_auction_schedule_gas_cost(&self)
640    }
641}
642
643impl GasCost for ActionDutchAuctionEnd {
644    fn gas_cost(&self) -> Gas {
645        dutch_auction_end_gas_cost()
646    }
647}
648
649impl GasCost for ActionDutchAuctionWithdraw {
650    fn gas_cost(&self) -> Gas {
651        dutch_auction_withdraw_gas_cost()
652    }
653}