Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement delegator slot reservation #4841

Open
wants to merge 45 commits into
base: feat-2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
79e9ea0
Add reservation test
j-chmielewski Jul 15, 2024
a79a677
Add Reservation type
j-chmielewski Jul 15, 2024
0da5531
Reservation variant for BidKind, BidKindTag enums
j-chmielewski Jul 15, 2024
66bc526
Merge branch 'whitelist-size' into reservation-list
j-chmielewski Jul 16, 2024
d9edb88
Merge branch 'whitelist-size' into reserved-slots
j-chmielewski Jul 22, 2024
7b68397
wip: initial implementation of has_reservation()
j-chmielewski Jul 24, 2024
0fb1130
Actually reserve slots
j-chmielewski Jul 24, 2024
fc9c39e
wip: handle add reservations
j-chmielewski Jul 24, 2024
5dabc2c
Add reservations entrypoint
j-chmielewski Jul 24, 2024
cef0dc2
Reservation storage support, passing engine test
j-chmielewski Jul 25, 2024
4151962
Serialization roundtrip test for `BidAddr::Reservation` variant
j-chmielewski Jul 25, 2024
13ca7e6
Cleanup
j-chmielewski Jul 25, 2024
ac52f48
wip: Add further ops to reservation test
j-chmielewski Jul 25, 2024
c30c169
Cancel reservation contract and entry point
j-chmielewski Jul 25, 2024
cfcf508
Implement cancel reservations contract and system methods
j-chmielewski Jul 25, 2024
2102947
Merge branch 'whitelist-size' into reserved-slots
j-chmielewski Jul 28, 2024
7b7216e
Update test
j-chmielewski Jul 28, 2024
109c4af
Reformat
j-chmielewski Jul 28, 2024
ed38783
Merge branch 'refs/heads/feat-2.0' into reserved-slots
Aug 27, 2024
7f8b56f
add more reservation test cases
Aug 28, 2024
9b8e7ac
validate max number of reservations
Aug 28, 2024
d3273d9
validate number of reserved slots
Aug 29, 2024
a2f65e5
validate reservation handling
Aug 29, 2024
fb07c3e
reverse order of commission calculations when distributing rewards
Aug 30, 2024
33f151a
add reservation delegation rates to `SeigniorageRecipient` struct
Aug 30, 2024
6145f7e
finish implementing rewards distribution
Aug 30, 2024
e2845f8
linter fixes
Aug 30, 2024
672254b
handle edge case when canceling reservation
Aug 30, 2024
431080d
Merge branch 'refs/heads/feat-2.0' into reserved-slots
Sep 3, 2024
2a259e6
fix failing test
Sep 3, 2024
f3fc48a
handle updating reservation delegation rate
Sep 3, 2024
d381cf7
fix outstanding todos
Sep 3, 2024
c5f6d0e
handle legacy and new version of seignorage snapshots
Sep 11, 2024
9f38960
add migration to handle creating initial version flag and new snapshot
Sep 13, 2024
19f2200
Merge branch 'refs/heads/feat-2.0' into reserved-slots
Sep 13, 2024
c901768
Merge branch 'refs/heads/feat-2.0' into reserved-slots
Oct 8, 2024
986b382
refactor expression for clarity
Oct 8, 2024
14a6ccc
refactor snapshot migration
Oct 10, 2024
4287239
test snapshot migration
Oct 10, 2024
514da4c
add logs
Oct 11, 2024
088afee
initialize snapshot version key
Oct 11, 2024
82bd2cb
get era validators from legacy snapshot
Oct 14, 2024
982c838
clear outstanding todos
Oct 14, 2024
77712fb
Merge branch 'feat-2.0' into reserved-slots
Oct 14, 2024
f29a832
add missing docstrings
Oct 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions execution_engine/src/runtime/auction_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,60 @@ where
Ok(keys.len())
}

fn reservation_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
let reservation_prefix = bid_addr.reservation_prefix()?;
let reservation_keys = self
.context
.get_keys_with_prefix(&reservation_prefix)
.map_err(|exec_error| {
error!("RuntimeProvider::reservation_count {:?}", exec_error);
<Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
})?;
Ok(reservation_keys.len())
}

fn used_reservation_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
let delegator_prefix = bid_addr.delegators_prefix()?;
let delegator_keys = self
.context
.get_keys_with_prefix(&delegator_prefix)
.map_err(|exec_error| {
error!("RuntimeProvider::used_reservation_count {:?}", exec_error);
<Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
})?;
let delegator_account_hashes: Vec<AccountHash> = delegator_keys
.into_iter()
.filter_map(|key| {
if let Key::BidAddr(BidAddr::Delegator { delegator, .. }) = key {
Some(delegator)
} else {
None
}
})
.collect();

let reservation_prefix = bid_addr.reservation_prefix()?;
let reservation_keys = self
.context
.get_keys_with_prefix(&reservation_prefix)
.map_err(|exec_error| {
error!("RuntimeProvider::reservation_count {:?}", exec_error);
<Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
})?;

let used_reservations_count = reservation_keys
.iter()
.filter(|reservation| {
if let Key::BidAddr(BidAddr::Reservation { delegator, .. }) = reservation {
delegator_account_hashes.contains(delegator)
} else {
false
}
})
.count();
Ok(used_reservations_count)
}

fn vesting_schedule_period_millis(&self) -> u64 {
self.context
.engine_config()
Expand Down
30 changes: 30 additions & 0 deletions execution_engine/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,9 @@ where
Self::try_get_named_argument(runtime_args, auction::ARG_RESERVED_SLOTS)?
.unwrap_or(0);

let max_delegators_per_validator =
self.context.engine_config().max_delegators_per_validator();

let result = runtime
.add_bid(
account_hash,
Expand All @@ -981,6 +984,7 @@ where
minimum_delegation_amount,
maximum_delegation_amount,
reserved_slots,
max_delegators_per_validator,
)
.map_err(Self::reverter)?;

Expand Down Expand Up @@ -1124,6 +1128,32 @@ where

CLValue::from_t(()).map_err(Self::reverter)
})(),
auction::METHOD_ADD_RESERVATIONS => (|| {
runtime.charge_system_contract_call(auction_costs.add_reservations)?;

let reservations =
Self::get_named_argument(runtime_args, auction::ARG_RESERVATIONS)?;

runtime
.add_reservations(reservations)
.map_err(Self::reverter)?;

CLValue::from_t(()).map_err(Self::reverter)
})(),
auction::METHOD_CANCEL_RESERVATIONS => (|| {
runtime.charge_system_contract_call(auction_costs.cancel_reservations)?;

let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
let delegators = Self::get_named_argument(runtime_args, auction::ARG_DELEGATORS)?;
let max_delegators_per_validator =
self.context.engine_config().max_delegators_per_validator();

runtime
.cancel_reservations(validator, delegators, max_delegators_per_validator)
.map_err(Self::reverter)?;

CLValue::from_t(()).map_err(Self::reverter)
})(),

_ => CLValue::from_t(()).map_err(Self::reverter),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use casper_storage::data_access_layer::{SlashItem, StepResult};
use casper_types::{
execution::TransformKindV2,
system::auction::{
BidsExt, DelegationRate, SeigniorageRecipientsSnapshot, SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
BidsExt, DelegationRate, SeigniorageRecipientsSnapshotV2,
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
},
CLValue, EntityAddr, EraId, GenesisAccount, GenesisValidator, Key, Motes, ProtocolVersion,
PublicKey, SecretKey, StoredValue, U512,
Expand Down Expand Up @@ -86,7 +87,7 @@ fn should_not_create_any_purse() {
.with_era_end_timestamp_millis(eras_end_timestamp_millis_1.as_millis().try_into().unwrap())
.build();

let before_auction_seigniorage: SeigniorageRecipientsSnapshot = builder.get_value(
let before_auction_seigniorage: SeigniorageRecipientsSnapshotV2 = builder.get_value(
EntityAddr::System(auction_hash.value()),
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
);
Expand Down Expand Up @@ -137,7 +138,7 @@ fn should_not_create_any_purse() {
);

// seigniorage snapshot should have changed after auction
let after_auction_seigniorage: SeigniorageRecipientsSnapshot = builder.get_value(
let after_auction_seigniorage: SeigniorageRecipientsSnapshotV2 = builder.get_value(
EntityAddr::System(auction_hash.value()),
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
);
Expand Down
6 changes: 3 additions & 3 deletions execution_engine_testing/tests/src/test/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use casper_storage::data_access_layer::SlashItem;
use casper_types::{
system::{
auction::{
BidsExt, DelegationRate, SeigniorageRecipientsSnapshot,
BidsExt, DelegationRate, SeigniorageRecipientsSnapshotV2,
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
},
mint::TOTAL_SUPPLY_KEY,
Expand Down Expand Up @@ -82,7 +82,7 @@ fn should_step() {

let auction_hash = builder.get_auction_contract_hash();

let before_auction_seigniorage: SeigniorageRecipientsSnapshot = builder.get_value(
let before_auction_seigniorage: SeigniorageRecipientsSnapshotV2 = builder.get_value(
EntityAddr::System(auction_hash.value()),
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
);
Expand All @@ -108,7 +108,7 @@ fn should_step() {
);

// seigniorage snapshot should have changed after auction
let after_auction_seigniorage: SeigniorageRecipientsSnapshot = builder.get_value(
let after_auction_seigniorage: SeigniorageRecipientsSnapshotV2 = builder.get_value(
EntityAddr::System(auction_hash.value()),
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use num_rational::Ratio;
use num_traits::{CheckedMul, CheckedSub};
use once_cell::sync::Lazy;

use crate::test::system_contracts::auction::{
get_delegator_staked_amount, get_era_info, get_validator_bid,
};
use casper_engine_test_support::{
ExecuteRequestBuilder, LmdbWasmTestBuilder, StepRequestBuilder, UpgradeRequestBuilder,
DEFAULT_ACCOUNT_ADDR, DEFAULT_GENESIS_TIMESTAMP_MILLIS, DEFAULT_LOCKED_FUNDS_PERIOD_MILLIS,
Expand All @@ -17,12 +20,12 @@ use casper_types::{
account::AccountHash,
runtime_args,
system::auction::{
self, BidsExt as _, DelegationRate, Delegator, EraInfo, SeigniorageAllocation,
SeigniorageRecipientsSnapshot, ValidatorBid, ARG_AMOUNT, ARG_DELEGATION_RATE,
ARG_DELEGATOR, ARG_PUBLIC_KEY, ARG_REWARDS_MAP, ARG_VALIDATOR, DELEGATION_RATE_DENOMINATOR,
self, BidsExt as _, DelegationRate, Delegator, SeigniorageAllocation,
SeigniorageRecipientsSnapshotV2, ARG_AMOUNT, ARG_DELEGATION_RATE, ARG_DELEGATOR,
ARG_PUBLIC_KEY, ARG_REWARDS_MAP, ARG_VALIDATOR, DELEGATION_RATE_DENOMINATOR,
METHOD_DISTRIBUTE, SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
},
EntityAddr, EraId, Key, ProtocolVersion, PublicKey, SecretKey, Timestamp, U512,
EntityAddr, EraId, ProtocolVersion, PublicKey, SecretKey, Timestamp, U512,
};

const ARG_ENTRY_POINT: &str = "entry_point";
Expand Down Expand Up @@ -71,14 +74,6 @@ static GENESIS_ROUND_SEIGNIORAGE_RATE: Lazy<Ratio<U512>> = Lazy::new(|| {
)
});

fn get_validator_bid(
builder: &mut LmdbWasmTestBuilder,
validator_public_key: PublicKey,
) -> Option<ValidatorBid> {
let bids = builder.get_bids();
bids.validator_bid(&validator_public_key)
}

fn get_delegator_bid(
builder: &mut LmdbWasmTestBuilder,
validator: PublicKey,
Expand Down Expand Up @@ -132,30 +127,6 @@ fn undelegate(
builder.exec(undelegate_request).expect_success().commit();
}

fn get_delegator_staked_amount(
builder: &mut LmdbWasmTestBuilder,
validator_public_key: PublicKey,
delegator_public_key: PublicKey,
) -> U512 {
let bids = builder.get_bids();
let delegator = bids
.delegator_by_public_keys(&validator_public_key, &delegator_public_key)
.expect("bid should exist for validator-{validator_public_key}, delegator-{delegator_public_key}");

delegator.staked_amount()
}

fn get_era_info(builder: &mut LmdbWasmTestBuilder) -> EraInfo {
let era_info_value = builder
.query(None, Key::EraSummary, &[])
.expect("should have value");

era_info_value
.as_era_info()
.cloned()
.expect("should be era info")
}

#[ignore]
#[test]
fn should_distribute_delegation_rate_zero() {
Expand Down Expand Up @@ -3289,7 +3260,7 @@ fn delegator_full_unbond_during_first_reward_era() {
// the delegator is scheduled to receive rewards this era.

let auction_hash = builder.get_auction_contract_hash();
let seigniorage_snapshot: SeigniorageRecipientsSnapshot = builder.get_value(
let seigniorage_snapshot: SeigniorageRecipientsSnapshotV2 = builder.get_value(
EntityAddr::System(auction_hash.value()),
SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,41 @@
use casper_engine_test_support::LmdbWasmTestBuilder;
use casper_types::{
system::auction::{BidsExt, EraInfo, ValidatorBid},
Key, PublicKey, U512,
};

mod bids;
mod distribute;
mod reservations;

fn get_validator_bid(
builder: &mut LmdbWasmTestBuilder,
validator_public_key: PublicKey,
) -> Option<ValidatorBid> {
let bids = builder.get_bids();
bids.validator_bid(&validator_public_key)
}

pub fn get_delegator_staked_amount(
builder: &mut LmdbWasmTestBuilder,
validator_public_key: PublicKey,
delegator_public_key: PublicKey,
) -> U512 {
let bids = builder.get_bids();
let delegator = bids
.delegator_by_public_keys(&validator_public_key, &delegator_public_key)
.expect("bid should exist for validator-{validator_public_key}, delegator-{delegator_public_key}");

delegator.staked_amount()
}

pub fn get_era_info(builder: &mut LmdbWasmTestBuilder) -> EraInfo {
let era_info_value = builder
.query(None, Key::EraSummary, &[])
.expect("should have value");

era_info_value
.as_era_info()
.cloned()
.expect("should be era info")
}
Loading
Loading