casper_storage/data_access_layer/
handle_refund.rs

1use crate::{
2    data_access_layer::BalanceIdentifier, system::runtime_native::Config as NativeRuntimeConfig,
3    tracking_copy::TrackingCopyError,
4};
5use casper_types::{
6    execution::Effects, Digest, InitiatorAddr, Phase, ProtocolVersion, TransactionHash, Transfer,
7    U512,
8};
9use num_rational::Ratio;
10
11/// Selects refund operation.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum HandleRefundMode {
14    /// This variant will cause the refund amount to be calculated and then burned.
15    Burn {
16        /// Refund limit.
17        limit: U512,
18        /// Refund cost.
19        cost: U512,
20        /// Refund consumed.
21        consumed: U512,
22        /// Refund gas price.
23        gas_price: u8,
24        /// Refund source.
25        source: Box<BalanceIdentifier>,
26        /// Refund ratio.
27        ratio: Ratio<u64>,
28    },
29    /// This variant will cause the refund amount to be calculated and the refund to be executed.
30    Refund {
31        /// Refund initiator.
32        initiator_addr: Box<InitiatorAddr>,
33        /// Refund limit.
34        limit: U512,
35        /// Refund cost.
36        cost: U512,
37        /// Refund consumed.
38        consumed: U512,
39        /// Refund gas price.
40        gas_price: u8,
41        /// Refund ratio.
42        ratio: Ratio<u64>,
43        /// Refund source.
44        source: Box<BalanceIdentifier>,
45        /// Target for refund.
46        target: Box<BalanceIdentifier>,
47    },
48    /// This variant handles the edge case of custom payment plus no fee plus no refund.
49    /// This ultimately turns into a hold on the initiator, but it takes extra steps to get there
50    /// because the payment has already been fully processed up front and must first be unwound.
51    RefundNoFeeCustomPayment {
52        /// Refund initiator.
53        initiator_addr: Box<InitiatorAddr>,
54        /// Refund limit.
55        limit: U512,
56        /// Refund cost.
57        cost: U512,
58        /// Refund gas price.
59        gas_price: u8,
60    },
61    /// This variant only calculates and returns the refund amount. It does not
62    /// execute a refund.
63    CalculateAmount {
64        /// Refund limit.
65        limit: U512,
66        /// Refund cost.
67        cost: U512,
68        /// Refund consumed.
69        consumed: U512,
70        /// Refund gas price.
71        gas_price: u8,
72        /// Refund ratio.
73        ratio: Ratio<u64>,
74        /// Refund source.
75        source: Box<BalanceIdentifier>,
76    },
77    /// This variant will cause the refund purse tracked by handle_payment to be set.
78    SetRefundPurse {
79        /// Target for refund, which will receive any refunded token while set.
80        target: Box<BalanceIdentifier>,
81    },
82    /// This variant will cause the refund purse tracked by handle_payment to be cleared.
83    ClearRefundPurse,
84}
85
86impl HandleRefundMode {
87    /// Returns the appropriate phase for the mode.
88    pub fn phase(&self) -> Phase {
89        match self {
90            HandleRefundMode::Burn { .. }
91            | HandleRefundMode::Refund { .. }
92            | HandleRefundMode::RefundNoFeeCustomPayment { .. }
93            | HandleRefundMode::CalculateAmount { .. } => Phase::FinalizePayment,
94
95            HandleRefundMode::ClearRefundPurse | HandleRefundMode::SetRefundPurse { .. } => {
96                Phase::Payment
97            }
98        }
99    }
100}
101
102/// Handle refund request.
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct HandleRefundRequest {
105    /// The runtime config.
106    pub(crate) config: NativeRuntimeConfig,
107    /// State root hash.
108    pub(crate) state_hash: Digest,
109    /// The protocol version.
110    pub(crate) protocol_version: ProtocolVersion,
111    /// Transaction hash.
112    pub(crate) transaction_hash: TransactionHash,
113    /// Refund handling.
114    pub(crate) refund_mode: HandleRefundMode,
115}
116
117impl HandleRefundRequest {
118    /// Creates a new instance.
119    pub fn new(
120        config: NativeRuntimeConfig,
121        state_hash: Digest,
122        protocol_version: ProtocolVersion,
123        transaction_hash: TransactionHash,
124        refund_mode: HandleRefundMode,
125    ) -> Self {
126        HandleRefundRequest {
127            config,
128            state_hash,
129            protocol_version,
130            transaction_hash,
131            refund_mode,
132        }
133    }
134
135    /// Returns a reference to the config.
136    pub fn config(&self) -> &NativeRuntimeConfig {
137        &self.config
138    }
139
140    /// Returns the state hash.
141    pub fn state_hash(&self) -> Digest {
142        self.state_hash
143    }
144
145    /// Returns the protocol version.
146    pub fn protocol_version(&self) -> ProtocolVersion {
147        self.protocol_version
148    }
149
150    /// Returns the transaction hash.
151    pub fn transaction_hash(&self) -> TransactionHash {
152        self.transaction_hash
153    }
154
155    /// Returns the refund mode.
156    pub fn refund_mode(&self) -> &HandleRefundMode {
157        &self.refund_mode
158    }
159}
160
161/// Handle refund result.
162#[derive(Debug)]
163pub enum HandleRefundResult {
164    /// Invalid state root hash.
165    RootNotFound,
166    /// Handle refund request succeeded.
167    Success {
168        /// Transfers.
169        transfers: Vec<Transfer>,
170        /// The effects.
171        effects: Effects,
172        /// The amount, if any.
173        amount: Option<U512>,
174    },
175    /// Invalid phase selected (programmer error).
176    InvalidPhase,
177    /// Handle refund request failed.
178    Failure(TrackingCopyError),
179}
180
181impl HandleRefundResult {
182    /// The effects, if any.
183    pub fn effects(&self) -> Effects {
184        match self {
185            HandleRefundResult::RootNotFound
186            | HandleRefundResult::InvalidPhase
187            | HandleRefundResult::Failure(_) => Effects::new(),
188            HandleRefundResult::Success { effects, .. } => effects.clone(),
189        }
190    }
191
192    /// The refund amount.
193    pub fn refund_amount(&self) -> U512 {
194        match self {
195            HandleRefundResult::RootNotFound
196            | HandleRefundResult::InvalidPhase
197            | HandleRefundResult::Failure(_) => U512::zero(),
198            HandleRefundResult::Success {
199                amount: refund_amount,
200                ..
201            } => refund_amount.unwrap_or(U512::zero()),
202        }
203    }
204
205    /// The error message, if any.
206    pub fn error_message(&self) -> Option<String> {
207        match self {
208            HandleRefundResult::RootNotFound => Some("root not found".to_string()),
209            HandleRefundResult::InvalidPhase => Some("invalid phase selected".to_string()),
210            HandleRefundResult::Failure(tce) => Some(format!("{}", tce)),
211            HandleRefundResult::Success { .. } => None,
212        }
213    }
214}