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#[derive(Clone, Eq, PartialEq, Error, Serialize, Debug)]
25pub enum AuctionMethodError {
26 #[error("invalid entry point for auction: {0}")]
28 InvalidEntryPoint(TransactionEntryPoint),
29 #[error("missing '{0}' arg")]
31 MissingArg(String),
32 #[error("failed to parse '{arg}' arg: {error}")]
34 CLValue {
35 arg: String,
37 error: CLValueError,
39 },
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum AuctionMethod {
45 ActivateBid {
47 validator: PublicKey,
49 },
50 AddBid {
52 public_key: PublicKey,
54 delegation_rate: DelegationRate,
56 amount: U512,
58 minimum_delegation_amount: u64,
60 maximum_delegation_amount: u64,
62 minimum_bid_amount: u64,
65 reserved_slots: u32,
67 },
68 WithdrawBid {
70 public_key: PublicKey,
72 amount: U512,
74 minimum_bid_amount: u64,
77 },
78 Delegate {
80 delegator: DelegatorKind,
82 validator: PublicKey,
84 amount: U512,
86 max_delegators_per_validator: u32,
88 },
89 Undelegate {
91 delegator: DelegatorKind,
93 validator: PublicKey,
95 amount: U512,
97 },
98 Redelegate {
101 delegator: DelegatorKind,
103 validator: PublicKey,
105 amount: U512,
107 new_validator: PublicKey,
109 },
110 ChangeBidPublicKey {
112 public_key: PublicKey,
114 new_public_key: PublicKey,
116 },
117 AddReservations {
119 reservations: Vec<Reservation>,
121 },
122 CancelReservations {
124 validator: PublicKey,
126 delegators: Vec<DelegatorKind>,
128 max_delegators_per_validator: u32,
130 },
131}
132
133impl AuctionMethod {
134 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#[derive(Debug, Clone, PartialEq, Eq)]
336pub struct BiddingRequest {
337 pub(crate) config: NativeRuntimeConfig,
339 pub(crate) state_hash: Digest,
341 pub(crate) protocol_version: ProtocolVersion,
343 pub(crate) auction_method: AuctionMethod,
345 pub(crate) transaction_hash: TransactionHash,
347 pub(crate) initiator: InitiatorAddr,
349 pub(crate) authorization_keys: BTreeSet<AccountHash>,
351}
352
353impl BiddingRequest {
354 #[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 pub fn config(&self) -> &NativeRuntimeConfig {
378 &self.config
379 }
380
381 pub fn state_hash(&self) -> Digest {
383 self.state_hash
384 }
385
386 pub fn protocol_version(&self) -> ProtocolVersion {
388 self.protocol_version
389 }
390
391 pub fn auction_method(&self) -> &AuctionMethod {
393 &self.auction_method
394 }
395
396 pub fn transaction_hash(&self) -> TransactionHash {
398 self.transaction_hash
399 }
400
401 pub fn initiator(&self) -> &InitiatorAddr {
403 &self.initiator
404 }
405
406 pub fn authorization_keys(&self) -> &BTreeSet<AccountHash> {
408 &self.authorization_keys
409 }
410}
411
412#[derive(Debug, Clone)]
414pub enum AuctionMethodRet {
415 Unit,
417 UpdatedAmount(U512),
419}
420
421#[derive(Debug)]
423pub enum BiddingResult {
424 RootNotFound,
426 Success {
428 transfers: Vec<Transfer>,
430 effects: Effects,
432 ret: AuctionMethodRet,
434 },
435 Failure(TrackingCopyError),
437}
438
439impl BiddingResult {
440 pub fn is_success(&self) -> bool {
442 matches!(self, BiddingResult::Success { .. })
443 }
444
445 pub fn effects(&self) -> Effects {
447 match self {
448 BiddingResult::RootNotFound | BiddingResult::Failure(_) => Effects::new(),
449 BiddingResult::Success { effects, .. } => effects.clone(),
450 }
451 }
452}