casper_storage/data_access_layer/
auction.rs

1use std::collections::BTreeSet;
2
3use serde::Serialize;
4use thiserror::Error;
5use tracing::error;
6
7use casper_types::{
8    account::AccountHash,
9    bytesrepr::FromBytes,
10    execution::Effects,
11    system::{
12        auction,
13        auction::{DelegationRate, DelegatorKind, Reservation},
14    },
15    CLTyped, CLValue, CLValueError, Chainspec, Digest, InitiatorAddr, ProtocolVersion, PublicKey,
16    RuntimeArgs, TransactionEntryPoint, TransactionHash, Transfer, URefAddr, U512,
17};
18
19use crate::{
20    system::runtime_native::Config as NativeRuntimeConfig, tracking_copy::TrackingCopyError,
21};
22
23/// An error returned when constructing an [`AuctionMethod`].
24#[derive(Clone, Eq, PartialEq, Error, Serialize, Debug)]
25pub enum AuctionMethodError {
26    /// Provided entry point is not one of the Auction ones.
27    #[error("invalid entry point for auction: {0}")]
28    InvalidEntryPoint(TransactionEntryPoint),
29    /// Required arg missing.
30    #[error("missing '{0}' arg")]
31    MissingArg(String),
32    /// Failed to parse the given arg.
33    #[error("failed to parse '{arg}' arg: {error}")]
34    CLValue {
35        /// The arg name.
36        arg: String,
37        /// The failure.
38        error: CLValueError,
39    },
40}
41
42/// Auction method to interact with.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum AuctionMethod {
45    /// Activate bid.
46    ActivateBid {
47        /// Validator public key (must match initiating address).
48        validator: PublicKey,
49    },
50    /// Add bid.
51    AddBid {
52        /// Validator public key (must match initiating address).
53        public_key: PublicKey,
54        /// Delegation rate for this validator bid.
55        delegation_rate: DelegationRate,
56        /// Bid amount.
57        amount: U512,
58        /// Minimum delegation amount for this validator bid.
59        minimum_delegation_amount: u64,
60        /// Maximum delegation amount for this validator bid.
61        maximum_delegation_amount: u64,
62        /// The minimum bid amount a validator must submit to have
63        /// their bid considered as valid.
64        minimum_bid_amount: u64,
65        /// Number of delegator slots which can be reserved for specific delegators
66        reserved_slots: u32,
67    },
68    /// Withdraw bid.
69    WithdrawBid {
70        /// Validator public key.
71        public_key: PublicKey,
72        /// Bid amount.
73        amount: U512,
74        /// The minimum bid amount a validator, if a validator reduces their stake
75        /// below this amount, then it is treated as a complete withdrawal.
76        minimum_bid_amount: u64,
77    },
78    /// Delegate to validator.
79    Delegate {
80        /// Delegator public key.
81        delegator: DelegatorKind,
82        /// Validator public key.
83        validator: PublicKey,
84        /// Delegation amount.
85        amount: U512,
86        /// Max delegators per validator.
87        max_delegators_per_validator: u32,
88    },
89    /// Undelegate from validator.
90    Undelegate {
91        /// Delegator public key.
92        delegator: DelegatorKind,
93        /// Validator public key.
94        validator: PublicKey,
95        /// Undelegation amount.
96        amount: U512,
97    },
98    /// Undelegate from validator and attempt delegation to new validator after unbonding delay
99    /// elapses.
100    Redelegate {
101        /// Delegator public key.
102        delegator: DelegatorKind,
103        /// Validator public key.
104        validator: PublicKey,
105        /// Redelegation amount.
106        amount: U512,
107        /// New validator public key.
108        new_validator: PublicKey,
109    },
110    /// Change the public key associated with a validator to a different public key.
111    ChangeBidPublicKey {
112        /// Current public key.
113        public_key: PublicKey,
114        /// New public key.
115        new_public_key: PublicKey,
116    },
117    /// Add delegator slot reservations.
118    AddReservations {
119        /// List of reservations.
120        reservations: Vec<Reservation>,
121    },
122    /// Remove delegator slot reservations for delegators with specified public keys.
123    CancelReservations {
124        /// Validator public key.
125        validator: PublicKey,
126        /// List of delegator public keys.
127        delegators: Vec<DelegatorKind>,
128        /// Max delegators per validator.
129        max_delegators_per_validator: u32,
130    },
131}
132
133impl AuctionMethod {
134    /// Form auction method from parts.
135    pub fn from_parts(
136        entry_point: TransactionEntryPoint,
137        runtime_args: &RuntimeArgs,
138        chainspec: &Chainspec,
139    ) -> Result<Self, AuctionMethodError> {
140        match entry_point {
141            TransactionEntryPoint::Call
142            | TransactionEntryPoint::Custom(_)
143            | TransactionEntryPoint::Transfer
144            | TransactionEntryPoint::Burn => {
145                Err(AuctionMethodError::InvalidEntryPoint(entry_point))
146            }
147            TransactionEntryPoint::ActivateBid => Self::new_activate_bid(runtime_args),
148            TransactionEntryPoint::AddBid => Self::new_add_bid(
149                runtime_args,
150                chainspec.core_config.minimum_delegation_amount,
151                chainspec.core_config.maximum_delegation_amount,
152                chainspec.core_config.minimum_bid_amount,
153            ),
154            TransactionEntryPoint::WithdrawBid => {
155                Self::new_withdraw_bid(runtime_args, chainspec.core_config.minimum_bid_amount)
156            }
157            TransactionEntryPoint::Delegate => Self::new_delegate(
158                runtime_args,
159                chainspec.core_config.max_delegators_per_validator,
160            ),
161            TransactionEntryPoint::Undelegate => Self::new_undelegate(runtime_args),
162            TransactionEntryPoint::Redelegate => Self::new_redelegate(runtime_args),
163            TransactionEntryPoint::ChangeBidPublicKey => {
164                Self::new_change_bid_public_key(runtime_args)
165            }
166            TransactionEntryPoint::AddReservations => Self::new_add_reservations(runtime_args),
167            TransactionEntryPoint::CancelReservations => Self::new_cancel_reservations(
168                runtime_args,
169                chainspec.core_config.max_delegators_per_validator,
170            ),
171        }
172    }
173
174    fn new_activate_bid(runtime_args: &RuntimeArgs) -> Result<Self, AuctionMethodError> {
175        let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
176        Ok(Self::ActivateBid { validator })
177    }
178
179    fn new_add_bid(
180        runtime_args: &RuntimeArgs,
181        global_minimum_delegation: u64,
182        global_maximum_delegation: u64,
183        global_minimum_bid_amount: u64,
184    ) -> Result<Self, AuctionMethodError> {
185        let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
186        let delegation_rate = Self::get_named_argument(runtime_args, auction::ARG_DELEGATION_RATE)?;
187        let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
188        let minimum_delegation_amount =
189            Self::get_named_argument(runtime_args, auction::ARG_MINIMUM_DELEGATION_AMOUNT)
190                .unwrap_or(global_minimum_delegation);
191        let maximum_delegation_amount =
192            Self::get_named_argument(runtime_args, auction::ARG_MAXIMUM_DELEGATION_AMOUNT)
193                .unwrap_or(global_maximum_delegation);
194        let reserved_slots =
195            Self::get_named_argument(runtime_args, auction::ARG_RESERVED_SLOTS).unwrap_or(0);
196
197        Ok(Self::AddBid {
198            public_key,
199            delegation_rate,
200            amount,
201            minimum_delegation_amount,
202            maximum_delegation_amount,
203            minimum_bid_amount: global_minimum_bid_amount,
204            reserved_slots,
205        })
206    }
207
208    fn new_withdraw_bid(
209        runtime_args: &RuntimeArgs,
210        global_minimum_bid_amount: u64,
211    ) -> Result<Self, AuctionMethodError> {
212        let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
213        let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
214        Ok(Self::WithdrawBid {
215            public_key,
216            amount,
217            minimum_bid_amount: global_minimum_bid_amount,
218        })
219    }
220
221    fn new_delegate(
222        runtime_args: &RuntimeArgs,
223        max_delegators_per_validator: u32,
224    ) -> Result<Self, AuctionMethodError> {
225        let delegator = {
226            match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
227                Ok(pk) => DelegatorKind::PublicKey(pk),
228                Err(_) => {
229                    let purse: URefAddr =
230                        Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR_PURSE)?;
231                    DelegatorKind::Purse(purse)
232                }
233            }
234        };
235        let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
236        let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
237
238        Ok(Self::Delegate {
239            delegator,
240            validator,
241            amount,
242            max_delegators_per_validator,
243        })
244    }
245
246    fn new_undelegate(runtime_args: &RuntimeArgs) -> Result<Self, AuctionMethodError> {
247        let delegator = {
248            match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
249                Ok(pk) => DelegatorKind::PublicKey(pk),
250                Err(_) => {
251                    let purse: URefAddr =
252                        Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR_PURSE)?;
253                    DelegatorKind::Purse(purse)
254                }
255            }
256        };
257        let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
258        let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
259
260        Ok(Self::Undelegate {
261            delegator,
262            validator,
263            amount,
264        })
265    }
266
267    fn new_redelegate(runtime_args: &RuntimeArgs) -> Result<Self, AuctionMethodError> {
268        let delegator = {
269            match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
270                Ok(pk) => DelegatorKind::PublicKey(pk),
271                Err(_) => {
272                    let purse: URefAddr =
273                        Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR_PURSE)?;
274                    DelegatorKind::Purse(purse)
275                }
276            }
277        };
278        let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
279        let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
280        let new_validator = Self::get_named_argument(runtime_args, auction::ARG_NEW_VALIDATOR)?;
281
282        Ok(Self::Redelegate {
283            delegator,
284            validator,
285            amount,
286            new_validator,
287        })
288    }
289
290    fn new_change_bid_public_key(runtime_args: &RuntimeArgs) -> Result<Self, AuctionMethodError> {
291        let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
292        let new_public_key = Self::get_named_argument(runtime_args, auction::ARG_NEW_PUBLIC_KEY)?;
293
294        Ok(Self::ChangeBidPublicKey {
295            public_key,
296            new_public_key,
297        })
298    }
299
300    fn new_add_reservations(runtime_args: &RuntimeArgs) -> Result<Self, AuctionMethodError> {
301        let reservations = Self::get_named_argument(runtime_args, auction::ARG_RESERVATIONS)?;
302
303        Ok(Self::AddReservations { reservations })
304    }
305
306    fn new_cancel_reservations(
307        runtime_args: &RuntimeArgs,
308        max_delegators_per_validator: u32,
309    ) -> Result<Self, AuctionMethodError> {
310        let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
311        let delegators = Self::get_named_argument(runtime_args, auction::ARG_DELEGATORS)?;
312
313        Ok(Self::CancelReservations {
314            validator,
315            delegators,
316            max_delegators_per_validator,
317        })
318    }
319
320    fn get_named_argument<T: FromBytes + CLTyped>(
321        args: &RuntimeArgs,
322        name: &str,
323    ) -> Result<T, AuctionMethodError> {
324        let arg: &CLValue = args
325            .get(name)
326            .ok_or_else(|| AuctionMethodError::MissingArg(name.to_string()))?;
327        arg.to_t().map_err(|error| AuctionMethodError::CLValue {
328            arg: name.to_string(),
329            error,
330        })
331    }
332}
333
334/// Bidding request.
335#[derive(Debug, Clone, PartialEq, Eq)]
336pub struct BiddingRequest {
337    /// The runtime config.
338    pub(crate) config: NativeRuntimeConfig,
339    /// State root hash.
340    pub(crate) state_hash: Digest,
341    /// The protocol version.
342    pub(crate) protocol_version: ProtocolVersion,
343    /// The auction method.
344    pub(crate) auction_method: AuctionMethod,
345    /// Transaction hash.
346    pub(crate) transaction_hash: TransactionHash,
347    /// Base account.
348    pub(crate) initiator: InitiatorAddr,
349    /// List of authorizing accounts.
350    pub(crate) authorization_keys: BTreeSet<AccountHash>,
351}
352
353impl BiddingRequest {
354    /// Creates new request instance with runtime args.
355    #[allow(clippy::too_many_arguments)]
356    pub fn new(
357        config: NativeRuntimeConfig,
358        state_hash: Digest,
359        protocol_version: ProtocolVersion,
360        transaction_hash: TransactionHash,
361        initiator: InitiatorAddr,
362        authorization_keys: BTreeSet<AccountHash>,
363        auction_method: AuctionMethod,
364    ) -> Self {
365        Self {
366            config,
367            state_hash,
368            protocol_version,
369            transaction_hash,
370            initiator,
371            authorization_keys,
372            auction_method,
373        }
374    }
375
376    /// Returns the config.
377    pub fn config(&self) -> &NativeRuntimeConfig {
378        &self.config
379    }
380
381    /// Returns the state hash.
382    pub fn state_hash(&self) -> Digest {
383        self.state_hash
384    }
385
386    /// Returns the protocol version.
387    pub fn protocol_version(&self) -> ProtocolVersion {
388        self.protocol_version
389    }
390
391    /// Returns the auction method.
392    pub fn auction_method(&self) -> &AuctionMethod {
393        &self.auction_method
394    }
395
396    /// Returns the transaction hash.
397    pub fn transaction_hash(&self) -> TransactionHash {
398        self.transaction_hash
399    }
400
401    /// Returns the initiator.
402    pub fn initiator(&self) -> &InitiatorAddr {
403        &self.initiator
404    }
405
406    /// Returns the authorization keys.
407    pub fn authorization_keys(&self) -> &BTreeSet<AccountHash> {
408        &self.authorization_keys
409    }
410}
411
412/// Auction method ret.
413#[derive(Debug, Clone)]
414pub enum AuctionMethodRet {
415    /// Unit.
416    Unit,
417    /// Updated amount.
418    UpdatedAmount(U512),
419}
420
421/// Bidding result.
422#[derive(Debug)]
423pub enum BiddingResult {
424    /// Invalid state root hash.
425    RootNotFound,
426    /// Bidding request succeeded
427    Success {
428        /// Transfer records.
429        transfers: Vec<Transfer>,
430        /// Effects of bidding interaction.
431        effects: Effects,
432        /// The ret value, if any.
433        ret: AuctionMethodRet,
434    },
435    /// Bidding request failed.
436    Failure(TrackingCopyError),
437}
438
439impl BiddingResult {
440    /// Is this a success.
441    pub fn is_success(&self) -> bool {
442        matches!(self, BiddingResult::Success { .. })
443    }
444
445    /// Effects.
446    pub fn effects(&self) -> Effects {
447        match self {
448            BiddingResult::RootNotFound | BiddingResult::Failure(_) => Effects::new(),
449            BiddingResult::Success { effects, .. } => effects.clone(),
450        }
451    }
452}