Skip to content

Commit 0679f48

Browse files
Fix override of delegator limits
1 parent 37fe0b4 commit 0679f48

7 files changed

Lines changed: 211 additions & 38 deletions

File tree

execution_engine/src/runtime/mod.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,23 +1066,15 @@ where
10661066
let minimum_delegation_amount = Self::try_get_named_argument(
10671067
runtime_args,
10681068
auction::ARG_MINIMUM_DELEGATION_AMOUNT,
1069-
)?
1070-
.unwrap_or(global_minimum_delegation_amount);
1069+
)?;
10711070

10721071
let global_maximum_delegation_amount =
10731072
self.context.engine_config().maximum_delegation_amount();
10741073
let maximum_delegation_amount = Self::try_get_named_argument(
10751074
runtime_args,
10761075
auction::ARG_MAXIMUM_DELEGATION_AMOUNT,
1077-
)?
1078-
.unwrap_or(global_maximum_delegation_amount);
1076+
)?;
10791077

1080-
if minimum_delegation_amount < global_minimum_delegation_amount
1081-
|| maximum_delegation_amount > global_maximum_delegation_amount
1082-
|| minimum_delegation_amount > maximum_delegation_amount
1083-
{
1084-
return Err(ExecError::Revert(ApiError::InvalidDelegationAmountLimits));
1085-
}
10861078
let reserved_slots =
10871079
Self::try_get_named_argument(runtime_args, auction::ARG_RESERVED_SLOTS)?
10881080
.unwrap_or(0);

execution_engine_testing/tests/src/test/system_contracts/auction/bids.rs

Lines changed: 134 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use casper_execution_engine::{
2121
engine_state::{engine_config::DEFAULT_MINIMUM_DELEGATION_AMOUNT, Error},
2222
execution::ExecError,
2323
};
24-
use casper_storage::data_access_layer::{GenesisRequest, HandleFeeMode};
24+
use casper_storage::data_access_layer::{AuctionMethod, GenesisRequest, HandleFeeMode};
2525

2626
use crate::lmdb_fixture;
2727
use casper_types::{
@@ -836,8 +836,8 @@ fn should_forcibly_undelegate_after_setting_validator_limits() {
836836
ARG_PUBLIC_KEY => NON_FOUNDER_VALIDATOR_1_PK.clone(),
837837
ARG_AMOUNT => U512::from(1_000),
838838
ARG_DELEGATION_RATE => ADD_BID_DELEGATION_RATE_1,
839-
ARG_MINIMUM_DELEGATION_AMOUNT => DELEGATE_AMOUNT_2 + 1_000,
840-
ARG_MAXIMUM_DELEGATION_AMOUNT => DELEGATE_AMOUNT_1 - 1_000,
839+
ARG_MINIMUM_DELEGATION_AMOUNT => DELEGATE_AMOUNT_2 + 1_000, // 100
840+
ARG_MAXIMUM_DELEGATION_AMOUNT => DELEGATE_AMOUNT_1 - 1_000, // 1000
841841
},
842842
)
843843
.build();
@@ -5961,3 +5961,134 @@ fn should_mark_bids_with_less_than_minimum_bid_amount_as_inactive_via_upgrade()
59615961

59625962
assert!(bid.inactive())
59635963
}
5964+
5965+
#[ignore]
5966+
#[test]
5967+
fn should_correctly_allow_validator_to_change_delegator_min_max_limits() {
5968+
let validator_1_fund_request = ExecuteRequestBuilder::standard(
5969+
*DEFAULT_ACCOUNT_ADDR,
5970+
CONTRACT_TRANSFER_TO_ACCOUNT,
5971+
runtime_args! {
5972+
ARG_TARGET => *NON_FOUNDER_VALIDATOR_1_ADDR,
5973+
ARG_AMOUNT => U512::from(TRANSFER_AMOUNT)
5974+
},
5975+
)
5976+
.build();
5977+
5978+
let mut builder = LmdbWasmTestBuilder::default();
5979+
5980+
builder.run_genesis(LOCAL_GENESIS_REQUEST.clone());
5981+
5982+
builder
5983+
.exec(validator_1_fund_request)
5984+
.expect_success()
5985+
.commit();
5986+
5987+
let result = builder.bidding(
5988+
None,
5989+
DEFAULT_PROTOCOL_VERSION,
5990+
(*NON_FOUNDER_VALIDATOR_1_ADDR).into(),
5991+
AuctionMethod::AddBid {
5992+
public_key: NON_FOUNDER_VALIDATOR_1_PK.clone(),
5993+
delegation_rate: 10,
5994+
amount: U512::from(ADD_BID_AMOUNT_1),
5995+
minimum_delegation_amount: Some(DEFAULT_MINIMUM_DELEGATION_AMOUNT + 10),
5996+
maximum_delegation_amount: Some(DEFAULT_MAXIMUM_DELEGATION_AMOUNT - 10),
5997+
minimum_bid_amount: DEFAULT_MINIMUM_BID_AMOUNT,
5998+
reserved_slots: 0,
5999+
},
6000+
);
6001+
6002+
assert!(result.is_success());
6003+
builder.commit_transforms(builder.get_post_state_hash(), result.effects());
6004+
let validator_public_key = NON_FOUNDER_VALIDATOR_1_PK.clone();
6005+
6006+
let bid = builder
6007+
.get_bids()
6008+
.into_iter()
6009+
.find(|bid| bid.validator_public_key() == validator_public_key)
6010+
.expect("must have bid for the validator")
6011+
.as_validator_bid()
6012+
.expect("must get validator bid");
6013+
6014+
assert_eq!(
6015+
bid.minimum_delegation_amount(),
6016+
DEFAULT_MINIMUM_DELEGATION_AMOUNT + 10
6017+
);
6018+
6019+
let result = builder.bidding(
6020+
None,
6021+
DEFAULT_PROTOCOL_VERSION,
6022+
(*NON_FOUNDER_VALIDATOR_1_ADDR).into(),
6023+
AuctionMethod::AddBid {
6024+
public_key: NON_FOUNDER_VALIDATOR_1_PK.clone(),
6025+
delegation_rate: 10,
6026+
amount: U512::from(ADD_BID_AMOUNT_1),
6027+
minimum_delegation_amount: Some(DEFAULT_MINIMUM_DELEGATION_AMOUNT + 5),
6028+
maximum_delegation_amount: None,
6029+
minimum_bid_amount: DEFAULT_MINIMUM_BID_AMOUNT,
6030+
reserved_slots: 0,
6031+
},
6032+
);
6033+
6034+
assert!(result.is_success());
6035+
builder.commit_transforms(builder.get_post_state_hash(), result.effects());
6036+
6037+
let validator_public_key = NON_FOUNDER_VALIDATOR_1_PK.clone();
6038+
6039+
let bid = builder
6040+
.get_bids()
6041+
.into_iter()
6042+
.find(|bid| bid.validator_public_key() == validator_public_key)
6043+
.expect("must have bid for the validator")
6044+
.as_validator_bid()
6045+
.expect("must get validator bid");
6046+
6047+
assert_eq!(
6048+
bid.minimum_delegation_amount(),
6049+
DEFAULT_MINIMUM_DELEGATION_AMOUNT + 5
6050+
);
6051+
6052+
assert_eq!(
6053+
bid.maximum_delegation_amount(),
6054+
DEFAULT_MAXIMUM_DELEGATION_AMOUNT - 10
6055+
);
6056+
6057+
let result = builder.bidding(
6058+
None,
6059+
DEFAULT_PROTOCOL_VERSION,
6060+
(*NON_FOUNDER_VALIDATOR_1_ADDR).into(),
6061+
AuctionMethod::AddBid {
6062+
public_key: NON_FOUNDER_VALIDATOR_1_PK.clone(),
6063+
delegation_rate: 10,
6064+
amount: U512::from(ADD_BID_AMOUNT_1),
6065+
minimum_delegation_amount: None,
6066+
maximum_delegation_amount: Some(DEFAULT_MAXIMUM_DELEGATION_AMOUNT - 5),
6067+
minimum_bid_amount: DEFAULT_MINIMUM_BID_AMOUNT,
6068+
reserved_slots: 0,
6069+
},
6070+
);
6071+
6072+
assert!(result.is_success());
6073+
builder.commit_transforms(builder.get_post_state_hash(), result.effects());
6074+
6075+
let validator_public_key = NON_FOUNDER_VALIDATOR_1_PK.clone();
6076+
6077+
let bid = builder
6078+
.get_bids()
6079+
.into_iter()
6080+
.find(|bid| bid.validator_public_key() == validator_public_key)
6081+
.expect("must have bid for the validator")
6082+
.as_validator_bid()
6083+
.expect("must get validator bid");
6084+
6085+
assert_eq!(
6086+
bid.minimum_delegation_amount(),
6087+
DEFAULT_MINIMUM_DELEGATION_AMOUNT + 5
6088+
);
6089+
6090+
assert_eq!(
6091+
bid.maximum_delegation_amount(),
6092+
DEFAULT_MAXIMUM_DELEGATION_AMOUNT - 5
6093+
);
6094+
}

execution_engine_testing/tests/src/test/system_contracts/auction/distribute.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,8 +998,8 @@ fn should_distribute_rewards_after_restaking_delegated_funds() {
998998
public_key: VALIDATOR_1.clone(),
999999
amount,
10001000
delegation_rate: 0,
1001-
minimum_delegation_amount: undelegate_amount.as_u64(),
1002-
maximum_delegation_amount: undelegate_amount.as_u64(),
1001+
minimum_delegation_amount: Some(undelegate_amount.as_u64()),
1002+
maximum_delegation_amount: Some(undelegate_amount.as_u64()),
10031003
minimum_bid_amount: DEFAULT_MINIMUM_BID_AMOUNT,
10041004
reserved_slots: 0,
10051005
}

storage/src/data_access_layer/auction.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ pub enum AuctionMethod {
5656
/// Bid amount.
5757
amount: U512,
5858
/// Minimum delegation amount for this validator bid.
59-
minimum_delegation_amount: u64,
59+
/// if provided by the user is set to Some
60+
minimum_delegation_amount: Option<u64>,
6061
/// Maximum delegation amount for this validator bid.
61-
maximum_delegation_amount: u64,
62+
/// if provided by the user is set to Some
63+
maximum_delegation_amount: Option<u64>,
6264
/// The minimum bid amount a validator must submit to have
6365
/// their bid considered as valid.
6466
minimum_bid_amount: u64,
@@ -145,12 +147,9 @@ impl AuctionMethod {
145147
Err(AuctionMethodError::InvalidEntryPoint(entry_point))
146148
}
147149
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-
),
150+
TransactionEntryPoint::AddBid => {
151+
Self::new_add_bid(runtime_args, chainspec.core_config.minimum_bid_amount)
152+
}
154153
TransactionEntryPoint::WithdrawBid => {
155154
Self::new_withdraw_bid(runtime_args, chainspec.core_config.minimum_bid_amount)
156155
}
@@ -178,19 +177,15 @@ impl AuctionMethod {
178177

179178
fn new_add_bid(
180179
runtime_args: &RuntimeArgs,
181-
global_minimum_delegation: u64,
182-
global_maximum_delegation: u64,
183180
global_minimum_bid_amount: u64,
184181
) -> Result<Self, AuctionMethodError> {
185182
let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
186183
let delegation_rate = Self::get_named_argument(runtime_args, auction::ARG_DELEGATION_RATE)?;
187184
let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
188185
let minimum_delegation_amount =
189-
Self::get_named_argument(runtime_args, auction::ARG_MINIMUM_DELEGATION_AMOUNT)
190-
.unwrap_or(global_minimum_delegation);
186+
Self::try_get_named_argument(runtime_args, auction::ARG_MINIMUM_DELEGATION_AMOUNT)?;
191187
let maximum_delegation_amount =
192-
Self::get_named_argument(runtime_args, auction::ARG_MAXIMUM_DELEGATION_AMOUNT)
193-
.unwrap_or(global_maximum_delegation);
188+
Self::try_get_named_argument(runtime_args, auction::ARG_MAXIMUM_DELEGATION_AMOUNT)?;
194189
let reserved_slots =
195190
Self::get_named_argument(runtime_args, auction::ARG_RESERVED_SLOTS).unwrap_or(0);
196191

@@ -329,6 +324,25 @@ impl AuctionMethod {
329324
error,
330325
})
331326
}
327+
328+
fn try_get_named_argument<T: FromBytes + CLTyped>(
329+
args: &RuntimeArgs,
330+
name: &str,
331+
) -> Result<Option<T>, AuctionMethodError> {
332+
match args.get(name) {
333+
Some(arg) => {
334+
let arg = arg
335+
.clone()
336+
.into_t()
337+
.map_err(|error| AuctionMethodError::CLValue {
338+
arg: name.to_string(),
339+
error,
340+
})?;
341+
Ok(Some(arg))
342+
}
343+
None => Ok(None),
344+
}
345+
}
332346
}
333347

334348
/// Bidding request.

storage/src/system/auction.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ pub trait Auction:
7373
public_key: PublicKey,
7474
delegation_rate: DelegationRate,
7575
amount: U512,
76-
minimum_delegation_amount: u64,
77-
maximum_delegation_amount: u64,
76+
minimum_delegation_amount: Option<u64>,
77+
maximum_delegation_amount: Option<u64>,
7878
minimum_bid_amount: u64,
7979
max_delegators_per_validator: u32,
8080
reserved_slots: u32,
@@ -105,11 +105,16 @@ pub trait Auction:
105105
return Err(Error::InvalidContext.into());
106106
}
107107

108-
if minimum_delegation_amount < global_minimum_delegation_amount
109-
|| maximum_delegation_amount > global_maximum_delegation_amount
110-
|| minimum_delegation_amount > maximum_delegation_amount
111-
{
112-
return Err(ApiError::InvalidDelegationAmountLimits);
108+
if let Some(minimum_delegation_amount) = minimum_delegation_amount {
109+
if minimum_delegation_amount < global_minimum_delegation_amount {
110+
return Err(ApiError::InvalidDelegationAmountLimits);
111+
}
112+
}
113+
114+
if let Some(maximum_delegation_amount) = maximum_delegation_amount {
115+
if maximum_delegation_amount > global_maximum_delegation_amount {
116+
return Err(ApiError::InvalidDelegationAmountLimits);
117+
}
113118
}
114119

115120
let validator_bid_key = BidAddr::from(public_key.clone()).into();
@@ -123,6 +128,15 @@ pub trait Auction:
123128
// idempotent
124129
validator_bid.activate();
125130

131+
let minimum_delegation_amount =
132+
minimum_delegation_amount.unwrap_or(validator_bid.minimum_delegation_amount());
133+
let maximum_delegation_amount =
134+
maximum_delegation_amount.unwrap_or(validator_bid.maximum_delegation_amount());
135+
136+
if maximum_delegation_amount < minimum_delegation_amount {
137+
return Err(ApiError::InvalidDelegationAmountLimits);
138+
}
139+
126140
validator_bid.with_delegation_rate(delegation_rate);
127141
process_updated_delegator_stake_boundaries(
128142
self,
@@ -141,6 +155,15 @@ pub trait Auction:
141155
if amount < U512::from(minimum_bid_amount) {
142156
return Err(Error::BondTooSmall.into());
143157
}
158+
let minimum_delegation_amount =
159+
minimum_delegation_amount.unwrap_or(global_minimum_delegation_amount);
160+
let maximum_delegation_amount =
161+
maximum_delegation_amount.unwrap_or(global_maximum_delegation_amount);
162+
163+
if maximum_delegation_amount < minimum_delegation_amount {
164+
return Err(ApiError::InvalidDelegationAmountLimits);
165+
}
166+
144167
// create new validator bid
145168
let bonding_purse = self.create_purse()?;
146169
let validator_bid = ValidatorBid::unlocked(

storage/src/system/auction/detail.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,13 +1369,16 @@ pub fn process_updated_delegator_stake_boundaries<P: Auction>(
13691369
return Err(Error::VestingLockout);
13701370
}
13711371

1372+
let previous_minimum = validator_bid.minimum_delegation_amount();
1373+
let previous_maximum = validator_bid.maximum_delegation_amount();
1374+
13721375
// set updated delegation amount range
13731376
validator_bid
13741377
.set_delegation_amount_boundaries(minimum_delegation_amount, maximum_delegation_amount);
13751378

13761379
// check modified delegation bookends
1377-
let raised_min = validator_bid.minimum_delegation_amount() < minimum_delegation_amount;
1378-
let lowered_max = validator_bid.maximum_delegation_amount() > maximum_delegation_amount;
1380+
let raised_min = previous_minimum < minimum_delegation_amount;
1381+
let lowered_max = previous_maximum > maximum_delegation_amount;
13791382
if !raised_min && !lowered_max {
13801383
return Ok(());
13811384
}

types/src/system/auction/bid_kind.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,16 @@ impl BidKind {
329329
| BidKind::Unbond(_) => None,
330330
}
331331
}
332+
333+
/// Returns a cloned validator bid.
334+
#[cfg(any(feature = "testing", test))]
335+
pub fn as_validator_bid(&self) -> Option<ValidatorBid> {
336+
if let Self::Validator(bid) = self {
337+
return Some(*bid.clone());
338+
}
339+
340+
None
341+
}
332342
}
333343

334344
impl CLTyped for BidKind {

0 commit comments

Comments
 (0)