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