Skip to content

Commit

Permalink
pos state machine: fix slashing computation
Browse files Browse the repository at this point in the history
  • Loading branch information
brentstone committed Jun 8, 2023
1 parent 2e13b48 commit 4ec81e2
Showing 1 changed file with 115 additions and 89 deletions.
204 changes: 115 additions & 89 deletions proof_of_stake/src/tests/state_machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ struct AbstractPosState {
/// Bonds delta values. The outer key for Epoch is pipeline offset from
/// epoch in which the bond is applied
bonds: BTreeMap<BondId, BTreeMap<Epoch, token::Change>>,
/// Total bonded tokens to a validator in each epoch. This is never
/// decremented and used for slashing computations.
total_bonded: BTreeMap<Address, BTreeMap<Epoch, token::Change>>,
/// Validator stakes. These are NOT deltas.
/// Pipelined.
validator_stakes: BTreeMap<Epoch, BTreeMap<Address, token::Change>>,
Expand Down Expand Up @@ -1927,6 +1930,14 @@ impl AbstractPosState {
if *bond == 0 {
bonds.remove(&pipeline_epoch);
}
// Update total_bonded
let total_bonded = self
.total_bonded
.entry(id.validator.clone())
.or_default()
.entry(self.pipeline())
.or_default();
*total_bonded += change;
}

fn update_state_with_unbond(&mut self, id: &BondId, change: token::Change) {
Expand Down Expand Up @@ -2250,8 +2261,11 @@ impl AbstractPosState {
tracing::debug!("Total rate: {}", total_rate);

let mut total_unbonded = token::Amount::default();
let mut sum_post_bonds = token::Change::default();

for epoch in (infraction_epoch.0 + 1)..self.epoch.0 {
tracing::debug!("\nEpoch {}", epoch);
let mut recent_unbonds = token::Change::default();
let unbond_records = self
.unbond_records
.entry(validator.clone())
Expand All @@ -2265,50 +2279,59 @@ impl AbstractPosState {
&unbond_amount,
&start
);
if start > infraction_epoch {
continue;
}
let slashes_for_this_unbond = self
.validator_slashes
.get(&validator)
.cloned()
.unwrap_or_default()
.iter()
.filter(|&s| {
start <= s.epoch
&& s.epoch
+ self.params.unbonding_len
+ self
.params
.cubic_slashing_window_length
< infraction_epoch
})
.cloned()
.fold(
BTreeMap::<Epoch, Decimal>::new(),
|mut acc, s| {
let cur = acc.entry(s.epoch).or_default();
*cur += s.rate;
acc
},
if start <= infraction_epoch {
let slashes_for_this_unbond = self
.validator_slashes
.get(&validator)
.cloned()
.unwrap_or_default()
.iter()
.filter(|&s| {
start <= s.epoch
&& s.epoch
+ self.params.unbonding_len
+ self
.params
.cubic_slashing_window_length
< infraction_epoch
})
.cloned()
.fold(
BTreeMap::<Epoch, Decimal>::new(),
|mut acc, s| {
let cur =
acc.entry(s.epoch).or_default();
*cur += s.rate;
acc
},
);
tracing::debug!(
"Slashes for this unbond: {:?}",
slashes_for_this_unbond
);
tracing::debug!(
"Slashes for this unbond: {:?}",
slashes_for_this_unbond
);
total_unbonded += compute_amount_after_slashing(
&slashes_for_this_unbond,
unbond_amount,
self.params.unbonding_len,
self.params.cubic_slashing_window_length,
);
total_unbonded += compute_amount_after_slashing(
&slashes_for_this_unbond,
unbond_amount,
self.params.unbonding_len,
self.params.cubic_slashing_window_length,
);
} else {
recent_unbonds += unbond_amount.change();
}

tracing::debug!(
"Total unbonded (epoch {}) w slashing = {}",
epoch,
total_unbonded
);
}
sum_post_bonds += *self
.total_bonded
.get(&validator)
.unwrap()
.get(&epoch)
.unwrap_or_default()
- recent_unbonds;
}
tracing::debug!("Computing adjusted amounts now");

Expand All @@ -2319,6 +2342,7 @@ impl AbstractPosState {
self.epoch + offset,
last_slash
);
let mut recent_unbonds = token::Change::default();
let unbond_records = self
.unbond_records
.get(&validator)
Expand All @@ -2332,45 +2356,47 @@ impl AbstractPosState {
&unbond_amount,
&start
);
if start > infraction_epoch {
continue;
}
if start <= infraction_epoch {
let slashes_for_this_unbond = self
.validator_slashes
.get(&validator)
.cloned()
.unwrap_or_default()
.iter()
.filter(|&s| {
start <= s.epoch
&& s.epoch
+ self.params.unbonding_len
+ self
.params
.cubic_slashing_window_length
< infraction_epoch
})
.cloned()
.fold(
BTreeMap::<Epoch, Decimal>::new(),
|mut acc, s| {
let cur =
acc.entry(s.epoch).or_default();
*cur += s.rate;
acc
},
);
tracing::debug!(
"Slashes for this unbond: {:?}",
slashes_for_this_unbond
);

let slashes_for_this_unbond = self
.validator_slashes
.get(&validator)
.cloned()
.unwrap_or_default()
.iter()
.filter(|&s| {
start <= s.epoch
&& s.epoch
+ self.params.unbonding_len
+ self
.params
.cubic_slashing_window_length
< infraction_epoch
})
.cloned()
.fold(
BTreeMap::<Epoch, Decimal>::new(),
|mut acc, s| {
let cur = acc.entry(s.epoch).or_default();
*cur += s.rate;
acc
},
total_unbonded += compute_amount_after_slashing(
&slashes_for_this_unbond,
unbond_amount,
self.params.unbonding_len,
self.params.cubic_slashing_window_length,
);
tracing::debug!(
"Slashes for this unbond: {:?}",
slashes_for_this_unbond
);
} else {
recent_unbonds += unbond_amount.change();
}

total_unbonded += compute_amount_after_slashing(
&slashes_for_this_unbond,
unbond_amount,
self.params.unbonding_len,
self.params.cubic_slashing_window_length,
);
tracing::debug!(
"Total unbonded (offset {}) w slashing = {}",
offset,
Expand All @@ -2386,7 +2412,7 @@ impl AbstractPosState {
total_rate,
stake_at_infraction - total_unbonded.change(),
);
let diff_slashed_amount = this_slash - last_slash;
let diff_slashed_amount = last_slash - this_slash;
tracing::debug!(
"Offset {} diff_slashed_amount {}",
offset,
Expand All @@ -2405,11 +2431,14 @@ impl AbstractPosState {
// *validator_stake -= diff_slashed_amount;

tracing::debug!("Updating ABSTRACT voting powers");
let sum_post_bonds = self.get_validator_bond_sums(
&validator,
infraction_epoch.next(),
self.epoch + offset,
);
sum_post_bonds += *self
.total_bonded
.get(&validator)
.unwrap()
.get(&epoch)
.unwrap_or_default()
- recent_unbonds;

tracing::debug!("\nUnslashable bonds = {}", sum_post_bonds);
let validator_stake_at_offset = self
.validator_stakes
Expand All @@ -2419,7 +2448,7 @@ impl AbstractPosState {
.or_default();

let slashable_stake_at_offset =
*validator_stake_at_offset - sum_post_bonds.change();
*validator_stake_at_offset - sum_post_bonds;
tracing::debug!(
"Val stake pre (epoch {}) = {}",
self.epoch + offset,
Expand All @@ -2429,16 +2458,13 @@ impl AbstractPosState {
"Slashable stake at offset = {}",
slashable_stake_at_offset
);
let change = if slashable_stake_at_offset
- diff_slashed_amount
< 0i128
{
slashable_stake_at_offset
} else {
diff_slashed_amount
};
let change = cmp::max(
-slashable_stake_at_offset,
diff_slashed_amount,
);

tracing::debug!("Change = {}", change);
*validator_stake_at_offset -= change;
*validator_stake_at_offset += change;

for os in (offset + 1)..=self.params.pipeline_len {
tracing::debug!("Adjust epoch {}", self.epoch + os);
Expand All @@ -2448,7 +2474,7 @@ impl AbstractPosState {
.or_default()
.entry(validator.clone())
.or_default();
*offset_stake -= change;
*offset_stake += change;
// let mut new_stake =
// *validator_stake - diff_slashed_amount;
// if new_stake < 0_i128 {
Expand Down

0 comments on commit 4ec81e2

Please sign in to comment.