From 7ceac79d65f04305a8bc8bc5c420780190ef9854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 2 May 2023 17:55:15 +0200 Subject: [PATCH] pos/epoched: add a test for epoched data trimming --- proof_of_stake/src/epoched.rs | 465 +++++++++++++++++++++++++++------- 1 file changed, 379 insertions(+), 86 deletions(-) diff --git a/proof_of_stake/src/epoched.rs b/proof_of_stake/src/epoched.rs index cc995559020..53a284a4873 100644 --- a/proof_of_stake/src/epoched.rs +++ b/proof_of_stake/src/epoched.rs @@ -671,89 +671,382 @@ pub trait EpochOffset: fn dyn_offset() -> DynEpochOffset; } -// mod test { -// use namada_core::ledger::storage::testing::TestStorage; -// 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(()) -// } -// } +#[cfg(test)] +mod test { + use namada_core::ledger::storage::testing::TestWlStorage; + use test_log::test; + + use super::*; + + #[test] + fn test_epoched_data_trimming() -> storage_api::Result<()> { + let mut s = TestWlStorage::default(); + + const NUM_PAST_EPOCHS: u64 = 2; + let key_prefix = storage::Key::parse("test").unwrap(); + let epoched = Epoched::::open( + key_prefix, + ); + let data_handler = epoched.get_data_handler(); + assert!(epoched.get_last_update(&s)?.is_none()); + assert!(epoched.get_oldest_epoch(&s)?.is_none()); + + epoched.set(&mut s, 0, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); + + epoched.set(&mut s, 1, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + + epoched.set(&mut s, 2, Epoch(1), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + + // Nothing is trimmed yet, oldest kept epoch is 0 + epoched.set(&mut s, 3, Epoch(2), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + + // Epoch 0 should be trimmed now, oldest kept epoch is 1 + epoched.set(&mut s, 4, Epoch(3), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(1))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, None); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + + // Anything before epoch 3 should be trimmed + epoched.set(&mut s, 5, Epoch(5), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(3))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, None); + assert_eq!(data_handler.get(&s, &Epoch(1))?, None); + assert_eq!(data_handler.get(&s, &Epoch(2))?, None); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); + + // Anything before epoch 8 should be trimmed + epoched.set(&mut s, 6, Epoch(10), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(8))); + for epoch in Epoch(0).iter_range(7) { + assert_eq!(data_handler.get(&s, &epoch)?, None); + } + // The value from the latest epoch 5 is assigned to epoch 8 + assert_eq!(data_handler.get(&s, &Epoch(8))?, Some(5)); + assert_eq!(data_handler.get(&s, &Epoch(9))?, None); + assert_eq!(data_handler.get(&s, &Epoch(10))?, Some(6)); + + Ok(()) + } + + #[test] + fn test_epoched_without_data_trimming() -> storage_api::Result<()> { + let mut s = TestWlStorage::default(); + + const NUM_PAST_EPOCHS: u64 = u64::MAX; + let key_prefix = storage::Key::parse("test").unwrap(); + let epoched = Epoched::::open( + key_prefix, + ); + let data_handler = epoched.get_data_handler(); + assert!(epoched.get_last_update(&s)?.is_none()); + assert!(epoched.get_oldest_epoch(&s)?.is_none()); + + epoched.set(&mut s, 0, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); + + epoched.set(&mut s, 1, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + + epoched.set(&mut s, 2, Epoch(1), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + + epoched.set(&mut s, 3, Epoch(2), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + + epoched.set(&mut s, 4, Epoch(3), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + + epoched.set(&mut s, 5, Epoch(5), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); + + epoched.set(&mut s, 6, Epoch(10), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); + assert_eq!(data_handler.get(&s, &Epoch(6))?, None); + assert_eq!(data_handler.get(&s, &Epoch(7))?, None); + assert_eq!(data_handler.get(&s, &Epoch(8))?, None); + assert_eq!(data_handler.get(&s, &Epoch(9))?, None); + assert_eq!(data_handler.get(&s, &Epoch(10))?, Some(6)); + + Ok(()) + } + + #[test] + fn test_epoched_delta_data_trimming() -> storage_api::Result<()> { + let mut s = TestWlStorage::default(); + + const NUM_PAST_EPOCHS: u64 = 2; + let key_prefix = storage::Key::parse("test").unwrap(); + let epoched = + EpochedDelta::::open( + key_prefix, + ); + let data_handler = epoched.get_data_handler(); + assert!(epoched.get_last_update(&s)?.is_none()); + assert!(epoched.get_oldest_epoch(&s)?.is_none()); + + epoched.set(&mut s, 0, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); + + epoched.set(&mut s, 1, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + + epoched.set(&mut s, 2, Epoch(1), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + + // Nothing is trimmed yet, oldest kept epoch is 0 + epoched.set(&mut s, 3, Epoch(2), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + + // Epoch 0 should be trimmed now, oldest kept epoch is 1 + epoched.set(&mut s, 4, Epoch(3), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(1))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, None); + // The value from epoch 0 should be added to epoch 1 + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + + // Anything before epoch 3 should be trimmed + epoched.set(&mut s, 5, Epoch(5), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(3))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, None); + assert_eq!(data_handler.get(&s, &Epoch(1))?, None); + assert_eq!(data_handler.get(&s, &Epoch(2))?, None); + // The values from epoch 1 and 2 should be added to epoch 3 + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(10)); + assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); + + // Anything before epoch 8 should be trimmed + epoched.set(&mut s, 6, Epoch(10), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(8))); + for epoch in Epoch(0).iter_range(7) { + assert_eq!(data_handler.get(&s, &epoch)?, None); + } + // The values from epoch 3 and 5 should be added to epoch 3 + assert_eq!(data_handler.get(&s, &Epoch(8))?, Some(15)); + assert_eq!(data_handler.get(&s, &Epoch(9))?, None); + assert_eq!(data_handler.get(&s, &Epoch(10))?, Some(6)); + + Ok(()) + } + + #[test] + fn test_epoched_delta_without_data_trimming() -> storage_api::Result<()> { + let mut s = TestWlStorage::default(); + + // Nothing should ever get trimmed + const NUM_PAST_EPOCHS: u64 = u64::MAX; + let key_prefix = storage::Key::parse("test").unwrap(); + let epoched = + EpochedDelta::::open( + key_prefix, + ); + let data_handler = epoched.get_data_handler(); + assert!(epoched.get_last_update(&s)?.is_none()); + assert!(epoched.get_oldest_epoch(&s)?.is_none()); + + epoched.set(&mut s, 0, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); + + epoched.set(&mut s, 1, Epoch(0), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + + epoched.set(&mut s, 2, Epoch(1), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + + epoched.set(&mut s, 3, Epoch(2), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + + epoched.set(&mut s, 4, Epoch(3), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + + epoched.set(&mut s, 5, Epoch(5), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); + + epoched.set(&mut s, 6, Epoch(10), 0)?; + assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); + assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); + assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); + assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); + assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); + assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); + assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); + assert_eq!(data_handler.get(&s, &Epoch(6))?, None); + assert_eq!(data_handler.get(&s, &Epoch(7))?, None); + assert_eq!(data_handler.get(&s, &Epoch(8))?, None); + assert_eq!(data_handler.get(&s, &Epoch(9))?, None); + assert_eq!(data_handler.get(&s, &Epoch(10))?, Some(6)); + + Ok(()) + } + + // use namada_core::ledger::storage::testing::TestStorage; + // 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(()) + // } +}