diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index c4abafeb9dd..7d8df912091 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -86,9 +86,6 @@ where height, current_epoch, new_epoch ); - println!("BYZANTINE VALIDATORS:"); - dbg!(&self.byzantine_validators); - if new_epoch { namada::ledger::storage::update_allowed_conversions( &mut self.wl_storage, @@ -503,12 +500,8 @@ where .update_epoch(height, header_time) .expect("Must be able to update epoch"); - println!("\nRECORDING SLASHES FROM EVIDENCE"); self.record_slashes_from_evidence(); - println!("\nPROCESSING SLASHES ENQUEUED FOR THIS EPOCH"); - self.process_slashes(); - println!("\nSLASHES PROCESSED"); (height, new_epoch) } @@ -819,7 +812,7 @@ mod test_finalize_block { read_consensus_validator_set_addresses_with_stake, read_num_consensus_validators, rewards_accumulator_handle, validator_consensus_key_handle, validator_rewards_products_handle, - validator_slashes_handle, validator_state_handle, + validator_slashes_handle, validator_state_handle, write_pos_params, }; use namada::types::governance::ProposalVote; use namada::types::storage::Epoch; @@ -1545,7 +1538,17 @@ mod test_finalize_block { votes: Vec, byzantine_validators: Option>, ) { + // Let the header time be always ahead of the next epoch min start time + let header = Header { + time: shell + .wl_storage + .storage + .next_epoch_min_start_time + .next_second(), + ..Default::default() + }; let mut req = FinalizeBlock { + header, proposer_address, votes, ..Default::default() @@ -1558,10 +1561,12 @@ mod test_finalize_block { } #[test] - fn test_ledger_slashing() { + fn test_ledger_slashing() -> storage_api::Result<()> { let num_validators = 7_u64; let (mut shell, _) = setup(num_validators); - let params = read_pos_params(&shell.wl_storage).unwrap(); + let mut params = read_pos_params(&shell.wl_storage).unwrap(); + params.unbonding_len = 4; + write_pos_params(&mut shell.wl_storage, params.clone()); let validator_set: Vec = read_consensus_validator_set_addresses_with_stake( @@ -1590,22 +1595,27 @@ mod test_finalize_block { HEXUPPER.decode(hash_string.as_bytes()).unwrap() }; - let mut pkhs: Vec> = Vec::new(); - for validator in &validator_set { + let mut all_pkhs: Vec> = Vec::new(); + let mut behaving_pkhs: Vec> = Vec::new(); + for (idx, validator) in validator_set.iter().enumerate() { assert_eq!( validator_state_handle(&validator.address) .get(&shell.wl_storage, Epoch::default(), ¶ms) .unwrap(), Some(ValidatorState::Consensus) ); - pkhs.push(get_pkh(validator.address.clone(), Epoch::default())); + all_pkhs.push(get_pkh(validator.address.clone(), Epoch::default())); + if idx > 1 as usize { + behaving_pkhs + .push(get_pkh(validator.address.clone(), Epoch::default())); + } } - let pkh1 = pkhs[0].clone(); - let _pkh2 = pkhs[1].clone(); + let pkh1 = all_pkhs[0].clone(); + let pkh2 = all_pkhs[1].clone(); // Finalize block 1 - next_block_for_inflation(&mut shell, pkh1, vec![], None); + next_block_for_inflation(&mut shell, pkh1.clone(), vec![], None); // for validator in &validator_set { // assert_eq!( // validator_state_handle(&validator.address) @@ -1616,10 +1626,7 @@ mod test_finalize_block { // pkhs.push(get_pkh(validator.address.clone(), Epoch::default())); // } - let pkh1 = pkhs[0].clone(); - let pkh2 = pkhs[1].clone(); - - let votes = get_default_votes(&pkhs, &validator_set); + let votes = get_default_true_votes(&all_pkhs, &validator_set); assert!(!votes.is_empty()); // For block 2, include the evidences found for block 1. Only the type, @@ -1648,7 +1655,7 @@ mod test_finalize_block { ]; next_block_for_inflation( &mut shell, - pkh1, + pkh1.clone(), votes, Some(byzantine_validators), ); @@ -1674,48 +1681,95 @@ mod test_finalize_block { Some(ValidatorState::Jailed) ); assert_eq!( - 5_u64, - read_num_consensus_validators(&shell.wl_storage).unwrap() + read_num_consensus_validators(&shell.wl_storage).unwrap(), + 5_u64 ); let processing_epoch = shell.wl_storage.storage.block.epoch + params.unbonding_len; - dbg!( - &enqueued_slashes_handle() - .at(&Epoch::default()) - .is_empty(&shell.wl_storage) - ); - dbg!( - &enqueued_slashes_handle() + for epoch in Epoch::default().iter_range(params.unbonding_len) { + assert!( + enqueued_slashes_handle() + .at(&epoch) + .is_empty(&shell.wl_storage)? + ); + } + assert!( + !enqueued_slashes_handle() .at(&processing_epoch) - .is_empty(&shell.wl_storage) + .is_empty(&shell.wl_storage)? + ); + assert!( + validator_slashes_handle(&val1.address) + .is_empty(&shell.wl_storage)? + ); + assert!( + validator_slashes_handle(&val2.address) + .is_empty(&shell.wl_storage)? ); - let all_slashes: Vec<_> = enqueued_slashes_handle() - .at(&processing_epoch) - .iter(&shell.wl_storage) - .unwrap() - .collect(); + // let enqueued_slashes: Vec<_> = enqueued_slashes_handle() + // .at(&processing_epoch) + // .iter(&shell.wl_storage) + // .unwrap() + // .collect(); - dbg!(&all_slashes); - let val1_slashes: Vec = validator_slashes_handle(&val1.address) - .iter(&shell.wl_storage) - .unwrap() - .map(|a| a.unwrap()) - .collect(); - let val2_slashes: Vec = validator_slashes_handle(&val2.address) - .iter(&shell.wl_storage) + let validator_set: Vec = + read_consensus_validator_set_addresses_with_stake( + &shell.wl_storage, + Epoch::default(), + ) .unwrap() - .map(|a| a.unwrap()) + .into_iter() .collect(); - dbg!(&val1_slashes, &val2_slashes); - assert!(val1_slashes.len() == 1 && val1_slashes[0].block_height == 1); - assert!(val2_slashes.len() == 1 && val2_slashes[0].block_height == 1); + let votes = get_default_true_votes(&behaving_pkhs, &validator_set); + loop { + next_block_for_inflation( + &mut shell, + pkh1.clone(), + votes.clone(), + None, + ); + if shell.wl_storage.storage.block.epoch == processing_epoch { + break; + } else { + println!( + "Block {} epoch {}", + shell.wl_storage.storage.block.height, + shell.wl_storage.storage.block.epoch + ); + assert!( + enqueued_slashes_handle() + .at(&shell.wl_storage.storage.block.epoch) + .is_empty(&shell.wl_storage)? + ); + } + } + assert!( + !validator_slashes_handle(&val1.address) + .is_empty(&shell.wl_storage)? + ); + assert!( + !validator_slashes_handle(&val2.address) + .is_empty(&shell.wl_storage)? + ); + + // let val1_slashes: Vec = + // validator_slashes_handle(&val1.address) .iter(&shell. + // wl_storage) .unwrap() + // .map(|a| a.unwrap()) + // .collect(); + // let val2_slashes: Vec = + // validator_slashes_handle(&val2.address) .iter(&shell. + // wl_storage) .unwrap() + // .map(|a| a.unwrap()) + // .collect(); + Ok(()) } - fn get_default_votes( + fn get_default_true_votes( addresses: &Vec>, powers: &Vec, ) -> Vec { diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index ce0bc5a5a87..5df35c791c6 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -427,7 +427,7 @@ where let pos_params = read_pos_params(&self.wl_storage).unwrap(); let current_epoch = self.wl_storage.storage.block.epoch; for evidence in byzantine_validators { - dbg!(&evidence); + // dbg!(&evidence); tracing::info!("Processing evidence {evidence:?}."); let evidence_height = match u64::try_from(evidence.height) { Ok(height) => height, diff --git a/core/src/ledger/storage_api/collections/lazy_map.rs b/core/src/ledger/storage_api/collections/lazy_map.rs index 836d9d88a16..d6f9c6cac48 100644 --- a/core/src/ledger/storage_api/collections/lazy_map.rs +++ b/core/src/ledger/storage_api/collections/lazy_map.rs @@ -418,11 +418,11 @@ where )?; Ok(iter.map(|key_val_res| { let (key, val) = key_val_res?; - dbg!(&key, &val); + // dbg!(&key, &val); let sub_key = LazyCollection::is_valid_sub_key(self, &key)? .ok_or(ReadError::UnexpectedlyEmptyStorageKey) .into_storage_result()?; - dbg!(&sub_key); + // dbg!(&sub_key); Ok((sub_key, val)) })) } @@ -631,28 +631,118 @@ mod test { } #[test] - fn test_nested_map() { + fn test_nested_map_basics() -> storage_api::Result<()> { let mut storage = TestWlStorage::default(); - let key = storage::Key::parse("testing").unwrap(); + + // A nested map from u32 -> String -> u32 let nested_map = - NestedMap::>>::open( - key.clone(), - ); + NestedMap::>::open(key.clone()); + + assert!(nested_map.is_empty(&storage)?); + assert!(nested_map.iter(&storage)?.next().is_none()); + + // Insert a value nested_map - .at(&0_u32) - .at(&"string1".to_string()) - .push(&mut storage, 100_u32) - .unwrap(); - - storage_api::iter_prefix_bytes(&storage, &key) - .unwrap() - .for_each(|a| { - dbg!(a); - }); - - nested_map.iter(&storage).unwrap().for_each(|a| { - dbg!(a); - }); + .at(&0) + .insert(&mut storage, "string1".to_string(), 100)?; + + assert!(!nested_map.is_empty(&storage)?); + assert!(nested_map.iter(&storage)?.next().is_some()); + assert_eq!( + nested_map.at(&0).get(&storage, &"string1".to_string())?, + Some(100) + ); + assert_eq!( + nested_map.at(&0).get(&storage, &"string2".to_string())?, + None + ); + + // Insert more values + nested_map + .at(&1) + .insert(&mut storage, "string1".to_string(), 200)?; + nested_map + .at(&0) + .insert(&mut storage, "string2".to_string(), 300)?; + + let mut it = nested_map.iter(&storage)?; + let ( + NestedSubKey::Data { + key, + nested_sub_key: SubKey::Data(inner_key), + }, + inner_val, + ) = it.next().unwrap()?; + assert_eq!(key, 0); + assert_eq!(inner_key, "string1".to_string()); + assert_eq!(inner_val, 100); + + let ( + NestedSubKey::Data { + key, + nested_sub_key: SubKey::Data(inner_key), + }, + inner_val, + ) = it.next().unwrap()?; + assert_eq!(key, 0); + assert_eq!(inner_key, "string2".to_string()); + assert_eq!(inner_val, 300); + + let ( + NestedSubKey::Data { + key, + nested_sub_key: SubKey::Data(inner_key), + }, + inner_val, + ) = it.next().unwrap()?; + assert_eq!(key, 1); + assert_eq!(inner_key, "string1".to_string()); + assert_eq!(inner_val, 200); + + // Next element should be None + assert!(it.next().is_none()); + drop(it); + + // Start removing elements + let rem = nested_map + .at(&0) + .remove(&mut storage, &"string2".to_string())?; + assert_eq!(rem, Some(300)); + assert_eq!( + nested_map.at(&0).get(&storage, &"string2".to_string())?, + None + ); + assert_eq!(nested_map.at(&0).len(&storage)?, 1_u64); + assert_eq!(nested_map.at(&1).len(&storage)?, 1_u64); + assert_eq!(nested_map.iter(&storage)?.count(), 2); + + // Start removing elements + let rem = nested_map + .at(&0) + .remove(&mut storage, &"string1".to_string())?; + assert_eq!(rem, Some(100)); + assert_eq!( + nested_map.at(&0).get(&storage, &"string1".to_string())?, + None + ); + assert_eq!(nested_map.at(&0).len(&storage)?, 0_u64); + assert_eq!(nested_map.at(&1).len(&storage)?, 1_u64); + assert_eq!(nested_map.iter(&storage)?.count(), 1); + + // Start removing elements + let rem = nested_map + .at(&1) + .remove(&mut storage, &"string1".to_string())?; + assert_eq!(rem, Some(200)); + assert_eq!( + nested_map.at(&1).get(&storage, &"string1".to_string())?, + None + ); + assert_eq!(nested_map.at(&0).len(&storage)?, 0_u64); + assert_eq!(nested_map.at(&1).len(&storage)?, 0_u64); + assert!(nested_map.is_empty(&storage)?); + + Ok(()) } } diff --git a/core/src/ledger/storage_api/collections/lazy_vec.rs b/core/src/ledger/storage_api/collections/lazy_vec.rs index bc74610097f..620945e9534 100644 --- a/core/src/ledger/storage_api/collections/lazy_vec.rs +++ b/core/src/ledger/storage_api/collections/lazy_vec.rs @@ -405,7 +405,7 @@ where { let len = self.len(storage)?; let data_key = self.get_data_key(len); - dbg!(&data_key, &val); + // dbg!(&data_key, &val); storage.write(&data_key, val)?; storage.write(&self.get_len_key(), len + 1) } diff --git a/core/src/ledger/storage_api/mod.rs b/core/src/ledger/storage_api/mod.rs index 6ecfafcf73a..d86537cefd7 100644 --- a/core/src/ledger/storage_api/mod.rs +++ b/core/src/ledger/storage_api/mod.rs @@ -156,7 +156,7 @@ where { let iter = storage.iter_prefix(prefix)?; let iter = itertools::unfold(iter, |iter| { - match dbg!(storage.iter_next(iter)) { + match storage.iter_next(iter) { Ok(Some((key, val))) => { let key = match storage::Key::parse(key).into_storage_result() { Ok(key) => key, @@ -184,6 +184,8 @@ where Ok(iter) } +/// Iterate Borsh encoded items matching the given prefix, additionally +/// satisfying some boolean filter function pub fn iter_prefix_with_filter<'a, T, F>( storage: &'a impl StorageRead, prefix: &crate::types::storage::Key, @@ -196,7 +198,7 @@ where let iter = storage.iter_prefix(prefix)?; let iter = itertools::unfold(iter, move |iter| { loop { - match dbg!(storage.iter_next(iter)) { + match storage.iter_next(iter) { Ok(Some((key, val))) => { let key = match storage::Key::parse(key).into_storage_result() { diff --git a/core/src/types/storage.rs b/core/src/types/storage.rs index 9655a7e107f..25827d8d769 100644 --- a/core/src/types/storage.rs +++ b/core/src/types/storage.rs @@ -277,7 +277,7 @@ impl core::fmt::Debug for BlockHash { /// The data from Tendermint header /// relevant for Namada storage -#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)] +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Default)] pub struct Header { /// Merkle root hash of block pub hash: Hash, @@ -915,6 +915,16 @@ impl Epoch { (start_ix..end_ix).map(Epoch::from) } + /// TODO + pub fn iter_bounds_inclusive( + start: Self, + end: Self, + ) -> impl Iterator + Clone { + let start_ix = start.0; + let end_ix = end.0; + (start_ix..=end_ix).map(Epoch::from) + } + /// Checked epoch subtraction. Computes self - rhs, returning None if /// overflow occurred. #[must_use = "this returns the result of the operation, without modifying \ diff --git a/core/src/types/time.rs b/core/src/types/time.rs index 72f7510e0be..c15e76884a3 100644 --- a/core/src/types/time.rs +++ b/core/src/types/time.rs @@ -96,7 +96,7 @@ impl From for DurationNanos { pub struct Rfc3339String(pub String); /// A duration in seconds precision. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DateTimeUtc(pub DateTime); impl DateTimeUtc { @@ -109,6 +109,11 @@ impl DateTimeUtc { pub fn to_rfc3339(&self) -> String { chrono::DateTime::to_rfc3339(&self.0) } + + /// Returns the DateTimeUtc corresponding to one second in the future + pub fn next_second(&self) -> Self { + *self + Duration::seconds(0) + } } impl FromStr for DateTimeUtc { diff --git a/proof_of_stake/src/epoched.rs b/proof_of_stake/src/epoched.rs index a523eff7eee..c6e79022f85 100644 --- a/proof_of_stake/src/epoched.rs +++ b/proof_of_stake/src/epoched.rs @@ -732,121 +732,121 @@ pub trait EpochOffset: fn dyn_offset() -> DynEpochOffset; } -mod test { - use namada_core::ledger::storage::testing::{TestStorage, TestWlStorage}; - use namada_core::ledger::storage_api::collections::LazyVec; - use namada_core::types::address::{self, Address}; - use namada_core::types::storage::Key; - - use super::{ - storage, storage_api, Epoch, LazyMap, NestedEpoched, NestedMap, - OffsetPipelineLen, - }; - - // #[test] - // fn testing_epoched_new() -> storage_api::Result<()> { - // let mut storage = TestStorage::default(); - - // let key1 = storage::Key::parse("test_nested1").unwrap(); - // let nested1 = - // NestedEpoched::, OffsetPipelineLen>::open( - // key1, - // ); - // nested1.init(&mut storage, Epoch(0))?; - - // let key2 = storage::Key::parse("test_nested2").unwrap(); - // let nested2 = NestedEpoched::< - // NestedMap>, - // OffsetPipelineLen, - // >::open(key2); - // nested2.init(&mut storage, Epoch(0))?; - - // dbg!(&nested1.get_last_update_storage_key()); - // dbg!(&nested1.get_last_update(&storage)); - - // nested1.at(&Epoch(0)).insert( - // &mut storage, - // address::testing::established_address_1(), - // 1432, - // )?; - // dbg!(&nested1.at(&Epoch(0)).iter(&mut storage)?.next()); - // dbg!(&nested1.at(&Epoch(1)).iter(&mut storage)?.next()); - - // nested2.at(&Epoch(0)).at(&100).insert( - // &mut storage, - // 1, - // address::testing::established_address_2(), - // )?; - // dbg!(&nested2.at(&Epoch(0)).iter(&mut storage)?.next()); - // dbg!(&nested2.at(&Epoch(1)).iter(&mut storage)?.next()); - - // dbg!(&nested_epoched.get_epoch_key(&Epoch::from(0))); - - // let epoch = Epoch::from(0); - // let addr = address::testing::established_address_1(); - // let amount: u64 = 234235; - - // nested_epoched - // .at(&epoch) - // .insert(&mut storage, addr.clone(), amount)?; - - // let epoch = epoch + 3_u64; - // nested_epoched.at(&epoch).insert( - // &mut storage, - // addr.clone(), - // 999_u64, - // )?; - - // dbg!(nested_epoched.contains_epoch(&storage, &Epoch::from(0))?); - // dbg!( - // nested_epoched - // .get_data_handler() - // .get_data_key(&Epoch::from(3)) - // ); - // dbg!(nested_epoched.contains_epoch(&storage, &Epoch::from(3))?); - // dbg!( - // nested_epoched - // .at(&Epoch::from(0)) - // .get(&storage, &addr.clone())? - // ); - // dbg!( - // nested_epoched - // .at(&Epoch::from(3)) - // .get(&storage, &addr.clone())? - // ); - // dbg!(nested_epoched.at(&Epoch::from(3)).get_data_key(&addr)); - - // Ok(()) - // } - - #[test] - fn test_nested_epoched_with_vec() { - let mut storage = TestWlStorage::default(); - - let key = storage::Key::parse("test_nested").unwrap(); - let nested = NestedEpoched::< - NestedMap>, - OffsetPipelineLen, - >::open(key); - nested.init(&mut storage, Epoch::default()).unwrap(); - - dbg!(&nested.get_last_update_storage_key()); - dbg!(&nested.get_last_update(&storage)); - - let addr = address::testing::established_address_1(); - - nested - .at(&Epoch::default()) - .at(&addr) - .push(&mut storage, "dangus".to_string()); - - dbg!(nested.get_data_handler().is_empty(&storage)); - nested - .get_data_handler() - .iter(&storage) - .unwrap() - .for_each(|a| { - dbg!(a); - }); - } -} +// mod test { +// use namada_core::ledger::storage::testing::{TestStorage, TestWlStorage}; +// use namada_core::ledger::storage_api::collections::LazyVec; +// use namada_core::types::address::{self, Address}; +// use namada_core::types::storage::Key; + +// use super::{ +// storage, storage_api, Epoch, LazyMap, NestedEpoched, NestedMap, +// OffsetPipelineLen, +// }; + +// #[test] +// fn testing_epoched_new() -> storage_api::Result<()> { +// let mut storage = TestStorage::default(); + +// let key1 = storage::Key::parse("test_nested1").unwrap(); +// let nested1 = +// NestedEpoched::, OffsetPipelineLen>::open( +// key1, +// ); +// nested1.init(&mut storage, Epoch(0))?; + +// let key2 = storage::Key::parse("test_nested2").unwrap(); +// let nested2 = NestedEpoched::< +// NestedMap>, +// OffsetPipelineLen, +// >::open(key2); +// nested2.init(&mut storage, Epoch(0))?; + +// dbg!(&nested1.get_last_update_storage_key()); +// dbg!(&nested1.get_last_update(&storage)); + +// nested1.at(&Epoch(0)).insert( +// &mut storage, +// address::testing::established_address_1(), +// 1432, +// )?; +// dbg!(&nested1.at(&Epoch(0)).iter(&mut storage)?.next()); +// dbg!(&nested1.at(&Epoch(1)).iter(&mut storage)?.next()); + +// nested2.at(&Epoch(0)).at(&100).insert( +// &mut storage, +// 1, +// address::testing::established_address_2(), +// )?; +// dbg!(&nested2.at(&Epoch(0)).iter(&mut storage)?.next()); +// dbg!(&nested2.at(&Epoch(1)).iter(&mut storage)?.next()); + +// dbg!(&nested_epoched.get_epoch_key(&Epoch::from(0))); + +// let epoch = Epoch::from(0); +// let addr = address::testing::established_address_1(); +// let amount: u64 = 234235; + +// nested_epoched +// .at(&epoch) +// .insert(&mut storage, addr.clone(), amount)?; + +// let epoch = epoch + 3_u64; +// nested_epoched.at(&epoch).insert( +// &mut storage, +// addr.clone(), +// 999_u64, +// )?; + +// dbg!(nested_epoched.contains_epoch(&storage, &Epoch::from(0))?); +// dbg!( +// nested_epoched +// .get_data_handler() +// .get_data_key(&Epoch::from(3)) +// ); +// dbg!(nested_epoched.contains_epoch(&storage, &Epoch::from(3))?); +// dbg!( +// nested_epoched +// .at(&Epoch::from(0)) +// .get(&storage, &addr.clone())? +// ); +// dbg!( +// nested_epoched +// .at(&Epoch::from(3)) +// .get(&storage, &addr.clone())? +// ); +// dbg!(nested_epoched.at(&Epoch::from(3)).get_data_key(&addr)); + +// Ok(()) +// } + +// #[test] +// fn test_nested_epoched_with_vec() { +// let mut storage = TestWlStorage::default(); + +// let key = storage::Key::parse("test_nested").unwrap(); +// let nested = NestedEpoched::< +// NestedMap>, +// OffsetPipelineLen, +// >::open(key); +// nested.init(&mut storage, Epoch::default()).unwrap(); + +// dbg!(&nested.get_last_update_storage_key()); +// dbg!(&nested.get_last_update(&storage)); + +// let addr = address::testing::established_address_1(); + +// nested +// .at(&Epoch::default()) +// .at(&addr) +// .push(&mut storage, "dangus".to_string()); + +// dbg!(nested.get_data_handler().is_empty(&storage)); +// nested +// .get_data_handler() +// .iter(&storage) +// .unwrap() +// .for_each(|a| { +// dbg!(a); +// }); +// } +// } diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 6178f008ed2..f0d616335b1 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -2679,10 +2679,12 @@ where { println!("COMPUTING CUBIC SLASH RATE"); let mut sum_vp_fraction = Decimal::ZERO; - let start_epoch = infraction_epoch - params.cubic_slashing_window_length; - let num_epochs = 2 * params.cubic_slashing_window_length + 1; + let start_epoch = infraction_epoch + .sub_or_default(Epoch(params.cubic_slashing_window_length)); + let end_epoch = infraction_epoch + params.cubic_slashing_window_length; - for epoch in Epoch::iter_range(start_epoch, num_epochs) { + for epoch in Epoch::iter_bounds_inclusive(start_epoch, end_epoch) { + dbg!(epoch); let total_stake = Decimal::from(read_total_stake(storage, params, epoch)?); let slashes = enqueued_slashes_handle().at(&epoch); @@ -2707,6 +2709,7 @@ where }); sum_vp_fraction += infracting_stake / total_stake; } + println!("Computed"); // TODO: make sure `sum_vp_fraction` does not exceed 1/3 or handle with care // another way Ok(dec!(9) * sum_vp_fraction * sum_vp_fraction) @@ -2734,7 +2737,8 @@ where } /// Record a slash for a misbehavior that has been received from Tendermint and -/// then jail the validator. The slash rate will be computed at a later epoch. +/// then jail the validator, removing it from the validator set. The slash rate +/// will be computed at a later epoch. pub fn slash( storage: &mut S, params: &PosParams, @@ -2747,10 +2751,6 @@ pub fn slash( where S: StorageRead + StorageWrite, { - // Upon slash detection, record the slash in storage for later processing, - // then jail the validator and immediately remove it from the validator - // set - println!("SLASHING ON NEW EVIDENCE"); let evidence_block_height: u64 = evidence_block_height.into();