Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions crates/config/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ build_config! {
(pos_cip156_transition_view, (u64), u64::MAX)
// 6 months with 30s rounds
(pos_cip156_dispute_locked_views, (u64), 6 * 30 * 24 * 60 * 2)
(pos_fix_cip156_transition_view, (u64), u64::MAX)
(dev_pos_private_key_encryption_password, (Option<String>), None)
(pos_started_as_voter, (bool), true)

Expand Down Expand Up @@ -1336,6 +1337,7 @@ impl Configuration {
self.raw_conf.pos_cip136_round_per_term,
self.raw_conf.pos_cip156_transition_view,
self.raw_conf.pos_cip156_dispute_locked_views,
self.raw_conf.pos_fix_cip156_transition_view,
)
}

Expand Down
9 changes: 8 additions & 1 deletion crates/pos/types/types/src/term_state/lock_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ impl StatusList {

pub fn len(&self) -> usize { self.inner.len() }

pub fn is_empty(&self) -> bool { self.inner.is_empty() }

pub fn iter(&self) -> Iter<'_, StatusItem> { self.inner.iter() }
}

Expand Down Expand Up @@ -279,7 +281,12 @@ impl NodeLockStatus {
match POS_STATE_CONFIG.dispute_locked_views(view) {
None => self.exempt_from_forfeit = Some(self.unlocked),
Some(dispute_locked_views) => {
if self.available_votes > 0 {
// available_votes excludes out_queue, so a fully-retired node
// (stake only in out_queue) escaped the lock before the fix.
let relock = self.available_votes > 0
|| (POS_STATE_CONFIG.dispute_lock_includes_out_queue(view)
&& !self.out_queue.is_empty());
if relock {
// We will lock all votes in `in_queue`, `locked`, and
// `out_queue`.
let mut to_lock_votes = self.available_votes;
Expand Down
12 changes: 11 additions & 1 deletion crates/pos/types/types/src/term_state/pos_state_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub struct PosStateConfig {

cip156_transition_view: u64,
cip156_dispute_locked_views: u64,
// After this view, a dispute also relocks a fully-retired node's
// out_queue.
fix_cip156_transition_view: u64,

nonce_limit_transition_view: u64,
max_nonce_per_account: u64,
Expand All @@ -52,6 +55,7 @@ pub trait PosStateConfigTrait {
// Returning None means the stake should be forfeited instead of being
// locked.
fn dispute_locked_views(&self, view: u64) -> Option<u64>;
fn dispute_lock_includes_out_queue(&self, view: u64) -> bool;
}

impl PosStateConfig {
Expand All @@ -63,7 +67,7 @@ impl PosStateConfig {
max_nonce_per_account: u64, cip136_transition_view: u64,
cip136_in_queue_locked_views: u64, cip136_out_queue_locked_views: u64,
cip136_round_per_term: u64, cip156_transition_view: u64,
cip156_dispute_locked_views: u64,
cip156_dispute_locked_views: u64, fix_cip156_transition_view: u64,
) -> Self {
Self {
round_per_term,
Expand All @@ -80,6 +84,7 @@ impl PosStateConfig {
cip136_round_per_term,
cip156_transition_view,
cip156_dispute_locked_views,
fix_cip156_transition_view,
nonce_limit_transition_view,
max_nonce_per_account,
}
Expand Down Expand Up @@ -208,6 +213,10 @@ impl PosStateConfigTrait for OnceCell<PosStateConfig> {
Some(conf.cip156_dispute_locked_views)
}
}

fn dispute_lock_includes_out_queue(&self, view: u64) -> bool {
view >= self.get().unwrap().fix_cip156_transition_view
}
}

pub static POS_STATE_CONFIG: OnceCell<PosStateConfig> = OnceCell::new();
Expand All @@ -229,6 +238,7 @@ impl Default for PosStateConfig {
cip136_round_per_term: ROUND_PER_TERM,
cip156_transition_view: u64::MAX,
cip156_dispute_locked_views: u64::MAX,
fix_cip156_transition_view: u64::MAX,
nonce_limit_transition_view: u64::MAX,
max_nonce_per_account: u64::MAX,
}
Expand Down
Loading