From 78fa8384f30e6cdcd9dbc1c44ddd818199556b91 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 14:24:45 +0000 Subject: [PATCH 01/69] stable balances --- Cargo.lock | 2 +- rs/ledger_suite/icrc1/ledger/src/lib.rs | 76 ++++++++++++++++++++++-- rs/ledger_suite/icrc1/ledger/src/main.rs | 17 +++++- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9b475264f0..cad39cd54bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14762,7 +14762,7 @@ dependencies = [ "regex", "regex-syntax 0.6.29", "string_cache", - "term 0.7.0", + "term", "tiny-keccak", "unicode-xid", ] diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index f08190eb7e3..622e13d6a6d 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -25,6 +25,7 @@ use ic_ledger_canister_core::{ ledger::{apply_transaction, block_locations, LedgerContext, LedgerData, TransactionInfo}, range_utils, }; +use ic_ledger_core::balances::BalancesStore; use ic_ledger_core::{ approvals::{Allowance, AllowanceTable, AllowancesData}, balances::Balances, @@ -82,11 +83,12 @@ pub type Tokens = ic_icrc1_tokens_u256::U256; /// We have the following ledger versions: /// * 0 - the whole ledger state is stored on the heap. /// * 1 - the allowances are stored in stable structures. +/// * 2 - the balances are stored in stable structures. #[cfg(not(feature = "next-ledger-version"))] -pub const LEDGER_VERSION: u64 = 1; +pub const LEDGER_VERSION: u64 = 2; #[cfg(feature = "next-ledger-version")] -pub const LEDGER_VERSION: u64 = 2; +pub const LEDGER_VERSION: u64 = 3; #[derive(Clone, Debug)] pub struct Icrc1ArchiveWasm; @@ -499,6 +501,7 @@ pub enum LedgerArgument { const UPGRADES_MEMORY_ID: MemoryId = MemoryId::new(0); const ALLOWANCES_MEMORY_ID: MemoryId = MemoryId::new(1); const ALLOWANCES_EXPIRATIONS_MEMORY_ID: MemoryId = MemoryId::new(2); +const BALANCES_MEMORY_ID: MemoryId = MemoryId::new(3); thread_local! { static MEMORY_MANAGER: RefCell> = RefCell::new( @@ -520,12 +523,17 @@ thread_local! { #[allow(clippy::type_complexity)] pub static ALLOWANCES_EXPIRATIONS_MEMORY: RefCell>> = MEMORY_MANAGER.with(|memory_manager| RefCell::new(StableBTreeMap::init(memory_manager.borrow().get(ALLOWANCES_EXPIRATIONS_MEMORY_ID)))); + + // account -> tokens - map storing ledger balances. + pub static BALANCES_MEMORY: RefCell>> = + MEMORY_MANAGER.with(|memory_manager| RefCell::new(StableBTreeMap::init(memory_manager.borrow().get(BALANCES_MEMORY_ID)))); } #[derive(Copy, Clone, Serialize, Deserialize, Debug)] pub enum LedgerField { Allowances, AllowancesExpirations, + Balances, } #[derive(Copy, Clone, Serialize, Deserialize, Debug)] @@ -540,11 +548,15 @@ impl Default for LedgerState { } } +type StableLedgerBalances = Balances; + #[derive(Debug, Deserialize, Serialize)] #[serde(bound = "")] pub struct Ledger { balances: LedgerBalances, #[serde(default)] + stable_balances: StableLedgerBalances, + #[serde(default)] approvals: LedgerAllowances, #[serde(default)] stable_approvals: AllowanceTable, @@ -643,6 +655,7 @@ impl Ledger { } let mut ledger = Self { balances: LedgerBalances::default(), + stable_balances: StableLedgerBalances::default(), approvals: Default::default(), stable_approvals: Default::default(), blockchain: Blockchain::new_with_archive(archive_options), @@ -719,6 +732,16 @@ impl Ledger { } } + pub fn migrate_one_balance(&mut self) -> bool { + match self.balances.store.pop_first() { + Some((account, tokens)) => { + self.stable_balances.credit(&account, tokens); + true + } + None => false, + } + } + pub fn clear_arrivals(&mut self) { self.approvals.allowances_data.clear_arrivals(); } @@ -727,17 +750,17 @@ impl Ledger { impl LedgerContext for Ledger { type AccountId = Account; type AllowancesData = StableAllowancesData; - type BalancesStore = BTreeMap; + type BalancesStore = StableBalances; type Tokens = Tokens; fn balances(&self) -> &Balances { panic_if_not_ready(); - &self.balances + &self.stable_balances } fn balances_mut(&mut self) -> &mut Balances { panic_if_not_ready(); - &mut self.balances + &mut self.stable_balances } fn approvals(&self) -> &AllowanceTable { @@ -1149,6 +1172,12 @@ pub fn clear_stable_allowance_data() { }); } +pub fn clear_stable_balances_data() { + BALANCES_MEMORY.with_borrow_mut(|balances| { + balances.clear_new(); + }); +} + #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} @@ -1273,3 +1302,40 @@ impl AllowancesData for StableAllowancesData { panic!("The method `clear_arrivals` should not be called for StableAllowancesData") } } + +#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] +pub struct StableBalances {} + +impl BalancesStore for StableBalances { + type AccountId = Account; + type Tokens = Tokens; + + fn get_balance(&self, k: &Account) -> Option { + BALANCES_MEMORY.with_borrow(|balances| balances.get(k)) + } + + fn update(&mut self, k: Account, mut f: F) -> Result + where + F: FnMut(Option<&Tokens>) -> Result, + { + let entry = BALANCES_MEMORY.with_borrow(|balances| balances.get(&k)); + match entry { + Some(v) => { + let new_v = f(Some(&v))?; + if new_v != Tokens::ZERO { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.insert(k, new_v)); + } else { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.remove(&k)); + } + Ok(new_v) + } + None => { + let new_v = f(None)?; + if new_v != Tokens::ZERO { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.insert(k, new_v)); + } + Ok(new_v) + } + } + } +} diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 999df760b49..24b54fb30ca 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -237,6 +237,11 @@ fn post_upgrade(args: Option) { PRE_UPGRADE_INSTRUCTIONS_CONSUMED.with(|n| *n.borrow_mut() = pre_upgrade_instructions_consumed); + if upgrade_from_version < 2 { + set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); + log_message("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data."); + clear_stable_balances_data(); + } if upgrade_from_version == 0 { set_ledger_state(LedgerState::Migrating(LedgerField::Allowances)); log_message("Upgrading from version 0 which does not use stable structures, clearing stable allowance data."); @@ -262,6 +267,7 @@ fn migrate_next_part(instruction_limit: u64) { STABLE_UPGRADE_MIGRATION_STEPS.with(|n| *n.borrow_mut() += 1); let mut migrated_allowances = 0; let mut migrated_expirations = 0; + let mut migrated_balances = 0; log_message("Migrating part of the ledger state."); @@ -284,6 +290,15 @@ fn migrate_next_part(instruction_limit: u64) { LedgerField::AllowancesExpirations => { if ledger.migrate_one_expiration() { migrated_expirations += 1; + } else { + set_ledger_state(LedgerState::Migrating( + LedgerField::Balances, + )); + } + } + LedgerField::Balances => { + if ledger.migrate_one_balance() { + migrated_balances += 1; } else { set_ledger_state(LedgerState::Ready); } @@ -291,7 +306,7 @@ fn migrate_next_part(instruction_limit: u64) { } } let instructions_migration = instruction_counter() - instructions_migration_start; - let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , + let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations} balances {migrated_balances}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , instruction_counter()); if !is_ready() { log_message( From 17135dd0ee03047dca82ccb291d9737b8f4aa5ae Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 15:51:16 +0000 Subject: [PATCH 02/69] remove account trimming --- .../common/ledger_canister_core/src/ledger.rs | 116 +----------------- .../common/ledger_core/src/balances.rs | 21 ---- rs/ledger_suite/icp/ledger/src/tests.rs | 65 ---------- rs/ledger_suite/icp/ledger/tests/tests.rs | 5 - rs/ledger_suite/icrc1/ledger/src/lib.rs | 8 ++ rs/ledger_suite/icrc1/ledger/src/main.rs | 13 +- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 5 - rs/ledger_suite/tests/sm-tests/src/lib.rs | 45 ------- 8 files changed, 16 insertions(+), 262 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index 08ee45f7605..e20c09c7409 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -4,22 +4,18 @@ use ic_canister_log::{log, Sink}; use ic_ledger_core::approvals::{ AllowanceTable, AllowancesData, ApproveError, InsufficientAllowance, }; -use ic_ledger_core::tokens::Zero; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, VecDeque}; use std::ops::Range; use std::time::Duration; use crate::archive::{ArchivingGuardError, FailedToArchiveBlocks, LedgerArchivingGuard}; -use ic_ledger_core::balances::{BalanceError, Balances, BalancesStore, InspectableBalancesStore}; +use ic_ledger_core::balances::{BalanceError, Balances, BalancesStore}; use ic_ledger_core::block::{BlockIndex, BlockType, EncodedBlock, FeeCollector}; use ic_ledger_core::timestamp::TimeStamp; use ic_ledger_core::tokens::TokensType; use ic_ledger_hash_of::HashOf; -/// The memo to use for balances burned and approvals reset to 0 during trimming -const TRIMMED_MEMO: u64 = u64::MAX; - #[derive(Debug, Deserialize, Serialize)] pub struct TransactionInfo { pub block_timestamp: TimeStamp, @@ -216,7 +212,6 @@ pub fn apply_transaction( ) -> Result<(BlockIndex, HashOf), TransferError> where L: LedgerData, - L::BalancesStore: InspectableBalancesStore, { let num_pruned = purge_old_transactions(ledger, now); @@ -301,82 +296,6 @@ where transaction_hash: tx_hash, }); } - let effective_max_number_of_accounts = - ledger.max_number_of_accounts() + ledger.accounts_overflow_trim_quantity() - 1; - - let to_trim = if ledger.balances().store.len() > effective_max_number_of_accounts { - select_accounts_to_trim(ledger) - } else { - vec![] - }; - - for (balance, account) in to_trim { - let burn_tx = L::Transaction::burn(account, None, balance, Some(now), Some(TRIMMED_MEMO)); - - burn_tx - .apply(ledger, now, L::Tokens::zero()) - .expect("failed to burn funds that must have existed"); - - let parent_hash = ledger.blockchain().last_hash; - let fee_collector = ledger.fee_collector().cloned(); - - ledger - .blockchain_mut() - .add_block(L::Block::from_transaction( - parent_hash, - burn_tx, - now, - L::Tokens::zero(), - fee_collector, - )) - .unwrap(); - } - - // We estimate that an approval takes up twice as much space as a balance: - // balance = account + num_tokens - // approval = 2 * account + num_tokens + timestamp - let max_number_of_approvals = - (effective_max_number_of_accounts - ledger.balances().store.len()) / 2; - - if ledger.approvals().len() > max_number_of_approvals { - let num_approvals_to_trim = ledger.approvals().len() - max_number_of_approvals; - // There might be some more expired approvals to prune. - ledger.approvals_mut().prune(now, num_approvals_to_trim); - - if ledger.approvals().len() > max_number_of_approvals { - let approvals_to_trim = ledger - .approvals() - .select_approvals_to_trim(ledger.approvals().len() - max_number_of_approvals); - - for approval in approvals_to_trim { - let approve_tx = L::Transaction::approve( - approval.0, - approval.1, - L::Tokens::zero(), - Some(now), - Some(TRIMMED_MEMO), - ); - - approve_tx - .apply(ledger, now, L::Tokens::zero()) - .expect("failed to reset approval to zero"); - - let parent_hash = ledger.blockchain().last_hash; - let fee_collector = ledger.fee_collector().cloned(); - - ledger - .blockchain_mut() - .add_block(L::Block::from_transaction( - parent_hash, - approve_tx, - now, - L::Tokens::zero(), - fee_collector, - )) - .unwrap(); - } - } - } Ok((height, ledger.blockchain().last_hash.unwrap())) } @@ -474,39 +393,6 @@ pub fn purge_old_transactions(ledger: &mut L, now: TimeStamp) -> num_tx_purged } -// Find the specified number of accounts with lowest balances so that their -// balances can be reclaimed. -fn select_accounts_to_trim(ledger: &L) -> Vec<(L::Tokens, L::AccountId)> -where - L: LedgerData, - L::BalancesStore: InspectableBalancesStore, - L::Tokens: TokensType, -{ - let mut to_trim: std::collections::BinaryHeap<(L::Tokens, L::AccountId)> = - std::collections::BinaryHeap::new(); - - let num_accounts = ledger.accounts_overflow_trim_quantity(); - let mut iter = ledger.balances().store.iter(); - - // Accumulate up to `trim_quantity` accounts - for (account, balance) in iter.by_ref().take(num_accounts) { - to_trim.push((balance.clone(), account.clone())); - } - - for (account, balance) in iter { - // If any account's balance is lower than the maximum in our set, - // include that account, and remove the current maximum - if let Some((greatest_balance, _)) = to_trim.peek() { - if balance < greatest_balance { - to_trim.push((balance.clone(), account.clone())); - to_trim.pop(); - } - } - } - - to_trim.into_vec() -} - /// Asynchronously archives a suffix of the locally available blockchain. /// /// NOTE: only one archiving task can run at each point in time. diff --git a/rs/ledger_suite/common/ledger_core/src/balances.rs b/rs/ledger_suite/common/ledger_core/src/balances.rs index 68d9791b879..cd229dfcabe 100644 --- a/rs/ledger_suite/common/ledger_core/src/balances.rs +++ b/rs/ledger_suite/common/ledger_core/src/balances.rs @@ -19,13 +19,6 @@ pub trait BalancesStore { F: FnMut(Option<&Self::Tokens>) -> Result; } -#[allow(clippy::len_without_is_empty)] -pub trait InspectableBalancesStore: BalancesStore { - fn iter(&self) -> Box + '_>; - - fn len(&self) -> usize; -} - impl BalancesStore for BTreeMap where AccountId: Eq + Clone + std::cmp::Ord, @@ -63,20 +56,6 @@ where } } -impl InspectableBalancesStore for BTreeMap -where - AccountId: Eq + Clone + std::cmp::Ord, - Tokens: TokensType, -{ - fn len(&self) -> usize { - self.len() - } - - fn iter(&self) -> Box + '_> { - Box::new(self.iter()) - } -} - /// An error returned by `Balances` if the debit operation fails. #[derive(Debug)] pub enum BalanceError { diff --git a/rs/ledger_suite/icp/ledger/src/tests.rs b/rs/ledger_suite/icp/ledger/src/tests.rs index d4838e9ce4e..42e0dedd66f 100644 --- a/rs/ledger_suite/icp/ledger/src/tests.rs +++ b/rs/ledger_suite/icp/ledger/src/tests.rs @@ -31,71 +31,6 @@ fn ts(n: u64) -> TimeStamp { TimeStamp::from_nanos_since_unix_epoch(n) } -#[test] -fn balances_overflow() { - let balances = LedgerBalances::new(); - let mut state = Ledger { - balances, - maximum_number_of_accounts: 8, - accounts_overflow_trim_quantity: 2, - minting_account_id: Some(PrincipalId::new_user_test_id(137).into()), - ..Default::default() - }; - assert_eq!(state.balances.token_pool, Tokens::MAX); - println!( - "minting canister initial balance: {}", - state.balances.token_pool - ); - let mut credited = Tokens::ZERO; - - // 11 accounts. The one with 0 will not be added - // The rest will be added and trigger a trim of 2 once - // the total number reaches 8 + 2 - // the number of active accounts won't go below 8 after trimming - for i in 0..11 { - let amount = Tokens::new(i, 0).unwrap(); - state - .add_payment( - Memo::default(), - Operation::Mint { - to: PrincipalId::new_user_test_id(i).into(), - amount, - }, - None, - ) - .unwrap(); - credited = credited.checked_add(&amount).unwrap(); - } - println!("amount credited to accounts: {}", credited); - - println!("balances: {:?}", state.balances); - - // The two accounts with lowest balances, 0 and 1 respectively, have been - // removed - assert_eq!(state.balances.store.len(), 8); - assert_eq!( - state - .balances - .account_balance(&PrincipalId::new_user_test_id(0).into()), - Tokens::ZERO - ); - assert_eq!( - state - .balances - .account_balance(&PrincipalId::new_user_test_id(1).into()), - Tokens::ZERO - ); - // We have credited 55 Tokens to various accounts but the three accounts - // with lowest balances, 0, 1 and 2, should have been removed and their - // balance returned to the minting canister - let expected_minting_canister_balance = Tokens::MAX - .checked_sub(&credited) - .unwrap() - .checked_add(&Tokens::new(1 + 2, 0).unwrap()) - .unwrap(); - assert_eq!(state.balances.token_pool, expected_minting_canister_balance); -} - #[test] fn balances_remove_accounts_with_zero_balance() { let mut ctx = Ledger::default(); diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 94db23d807e..7112784618b 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1502,11 +1502,6 @@ fn test_transfer_from_burn() { ic_ledger_suite_state_machine_tests::test_transfer_from_burn(ledger_wasm(), encode_init_args); } -#[test] -fn test_balances_overflow() { - ic_ledger_suite_state_machine_tests::test_balances_overflow(ledger_wasm(), encode_init_args); -} - #[test] fn test_approval_trimming() { ic_ledger_suite_state_machine_tests::test_approval_trimming( diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 622e13d6a6d..b8bcc347859 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -745,6 +745,10 @@ impl Ledger { pub fn clear_arrivals(&mut self) { self.approvals.allowances_data.clear_arrivals(); } + + pub fn copy_token_pool(&mut self) { + self.stable_balances.token_pool = self.balances.token_pool; + } } impl LedgerContext for Ledger { @@ -1178,6 +1182,10 @@ pub fn clear_stable_balances_data() { }); } +pub fn balances_len() -> u64 { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) +} + #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 24b54fb30ca..21cdfe1c34d 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -16,8 +16,8 @@ use ic_icrc1::{ Operation, Transaction, }; use ic_icrc1_ledger::{ - clear_stable_allowance_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, - LEDGER_VERSION, UPGRADES_MEMORY, + balances_len, clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, + panic_if_not_ready, set_ledger_state, LEDGER_VERSION, UPGRADES_MEMORY, }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; use ic_ledger_canister_core::ledger::{ @@ -241,6 +241,9 @@ fn post_upgrade(args: Option) { set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); log_message("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data."); clear_stable_balances_data(); + Access::with_ledger_mut(|ledger| { + ledger.copy_token_pool(); + }); } if upgrade_from_version == 0 { set_ledger_state(LedgerState::Migrating(LedgerField::Allowances)); @@ -291,9 +294,7 @@ fn migrate_next_part(instruction_limit: u64) { if ledger.migrate_one_expiration() { migrated_expirations += 1; } else { - set_ledger_state(LedgerState::Migrating( - LedgerField::Balances, - )); + set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); } } LedgerField::Balances => { @@ -418,7 +419,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - ledger.balances().store.len() as f64, + balances_len() as f64, "Total number of accounts in the balance store.", )?; } diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index a098a08da8b..cd7d0ce58a0 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -390,11 +390,6 @@ fn test_transfer_from_burn() { ic_ledger_suite_state_machine_tests::test_transfer_from_burn(ledger_wasm(), encode_init_args); } -#[test] -fn test_balances_overflow() { - ic_ledger_suite_state_machine_tests::test_balances_overflow(ledger_wasm(), encode_init_args); -} - #[test] fn test_approval_trimming() { ic_ledger_suite_state_machine_tests::test_approval_trimming( diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 71c412e9af3..c1bff467889 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3822,51 +3822,6 @@ where assert_eq!(total_supply(&env, canister_id), 60_000); } -pub fn test_balances_overflow(ledger_wasm: Vec, encode_init_args: fn(InitArgs) -> T) -where - T: CandidType, -{ - let env = StateMachine::new(); - - let args = encode_init_args(InitArgs { - maximum_number_of_accounts: Some(8), - accounts_overflow_trim_quantity: Some(2), - ..init_args(vec![]) - }); - let args = Encode!(&args).unwrap(); - let canister_id = env.install_canister(ledger_wasm, args, None).unwrap(); - - let minter = minting_account(&env, canister_id).unwrap(); - - let mut credited = 0; - for i in 0..11 { - transfer( - &env, - canister_id, - minter, - PrincipalId::new_user_test_id(i).0, - i, - ) - .expect("failed to mint tokens"); - credited += i; - } - assert_eq!( - balance_of(&env, canister_id, PrincipalId::new_user_test_id(1).0), - 0 - ); - assert_eq!( - balance_of(&env, canister_id, PrincipalId::new_user_test_id(2).0), - 0 - ); - for i in 3..11 { - assert_eq!( - balance_of(&env, canister_id, PrincipalId::new_user_test_id(i).0), - i - ); - } - assert_eq!(total_supply(&env, canister_id), credited - 1 - 2); -} - pub fn test_approval_trimming( ledger_wasm: Vec, encode_init_args: fn(InitArgs) -> T, From 996abf8d647f39e2d2dd8fb820d9b5f17906991c Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 15:54:38 +0000 Subject: [PATCH 03/69] clippy --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index b8bcc347859..c519882153f 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -748,7 +748,7 @@ impl Ledger { pub fn copy_token_pool(&mut self) { self.stable_balances.token_pool = self.balances.token_pool; - } + } } impl LedgerContext for Ledger { From 84551a9109d4ba4e182fadc89c5af6a4a92d4041 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 16:04:47 +0000 Subject: [PATCH 04/69] build fix --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 2 +- rs/ledger_suite/icrc1/ledger/src/lib.rs | 8 ++++---- rs/ledger_suite/icrc1/ledger/src/main.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index f99196d8c27..a85c3146b58 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -43,7 +43,7 @@ pub fn icrc1_transfer( fn assert_has_num_balances(num_balances: u32) { Access::with_ledger(|ledger| { - assert_eq!(ledger.balances().store.len() as u32, num_balances); + assert_eq!(ledger.balances_len() as u32, num_balances); }); } diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index c519882153f..3e450ffba93 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -749,6 +749,10 @@ impl Ledger { pub fn copy_token_pool(&mut self) { self.stable_balances.token_pool = self.balances.token_pool; } + + pub fn balances_len(&self) -> u64{ + BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) + } } impl LedgerContext for Ledger { @@ -1182,10 +1186,6 @@ pub fn clear_stable_balances_data() { }); } -pub fn balances_len() -> u64 { - BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) -} - #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 21cdfe1c34d..106b3f88fac 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -16,7 +16,7 @@ use ic_icrc1::{ Operation, Transaction, }; use ic_icrc1_ledger::{ - balances_len, clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, + clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, LEDGER_VERSION, UPGRADES_MEMORY, }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; @@ -419,7 +419,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - balances_len() as f64, + ledger.balances_len() as f64, "Total number of accounts in the balance store.", )?; } From 1005cb5bb9bc8f16657ee560c47301b3a0ae7346 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 16:07:41 +0000 Subject: [PATCH 05/69] clippy --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 3e450ffba93..36f917a6bba 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -750,7 +750,7 @@ impl Ledger { self.stable_balances.token_pool = self.balances.token_pool; } - pub fn balances_len(&self) -> u64{ + pub fn balances_len(&self) -> u64 { BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) } } From 33cfeb16a0fe8647a0bdd26459d8356ccd521948 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 16:18:25 +0000 Subject: [PATCH 06/69] clippy --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index a85c3146b58..64243e0807f 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -3,7 +3,7 @@ use assert_matches::assert_matches; use candid::{Nat, Principal}; use ic_canister_log::Sink; use ic_ledger_canister_core::ledger::{ - blocks_to_archive, remove_archived_blocks, LedgerAccess, LedgerContext, + blocks_to_archive, remove_archived_blocks, LedgerAccess, }; use ic_ledger_core::block::BlockIndex; use icrc_ledger_types::icrc1::account::Account; From e0ad62b8fa35171a485985cfb0d65a253b9fa37c Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 29 Nov 2024 16:23:58 +0000 Subject: [PATCH 07/69] clippy --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index 64243e0807f..d05c743c304 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -2,9 +2,7 @@ use crate::{execute_transfer_not_async, post_upgrade, pre_upgrade, Access, Token use assert_matches::assert_matches; use candid::{Nat, Principal}; use ic_canister_log::Sink; -use ic_ledger_canister_core::ledger::{ - blocks_to_archive, remove_archived_blocks, LedgerAccess, -}; +use ic_ledger_canister_core::ledger::{blocks_to_archive, remove_archived_blocks, LedgerAccess}; use ic_ledger_core::block::BlockIndex; use icrc_ledger_types::icrc1::account::Account; use icrc_ledger_types::icrc1::transfer::TransferArg; From 9de583d602abab6bda6359907a30bb3f7dce6bfe Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Sat, 30 Nov 2024 16:12:08 +0000 Subject: [PATCH 08/69] Revert "clippy" This reverts commit e0ad62b8fa35171a485985cfb0d65a253b9fa37c. --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index d05c743c304..64243e0807f 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -2,7 +2,9 @@ use crate::{execute_transfer_not_async, post_upgrade, pre_upgrade, Access, Token use assert_matches::assert_matches; use candid::{Nat, Principal}; use ic_canister_log::Sink; -use ic_ledger_canister_core::ledger::{blocks_to_archive, remove_archived_blocks, LedgerAccess}; +use ic_ledger_canister_core::ledger::{ + blocks_to_archive, remove_archived_blocks, LedgerAccess, +}; use ic_ledger_core::block::BlockIndex; use icrc_ledger_types::icrc1::account::Account; use icrc_ledger_types::icrc1::transfer::TransferArg; From 5562268aaa0a8004eec20fee757011e478c4195a Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Sat, 30 Nov 2024 16:12:25 +0000 Subject: [PATCH 09/69] Revert "clippy" This reverts commit 33cfeb16a0fe8647a0bdd26459d8356ccd521948. --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index 64243e0807f..a85c3146b58 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -3,7 +3,7 @@ use assert_matches::assert_matches; use candid::{Nat, Principal}; use ic_canister_log::Sink; use ic_ledger_canister_core::ledger::{ - blocks_to_archive, remove_archived_blocks, LedgerAccess, + blocks_to_archive, remove_archived_blocks, LedgerAccess, LedgerContext, }; use ic_ledger_core::block::BlockIndex; use icrc_ledger_types::icrc1::account::Account; From a917348c034b9bc2f17feefe52fdf8f1ee582a8d Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Sat, 30 Nov 2024 16:12:35 +0000 Subject: [PATCH 10/69] Revert "clippy" This reverts commit 1005cb5bb9bc8f16657ee560c47301b3a0ae7346. --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 36f917a6bba..3e450ffba93 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -750,7 +750,7 @@ impl Ledger { self.stable_balances.token_pool = self.balances.token_pool; } - pub fn balances_len(&self) -> u64 { + pub fn balances_len(&self) -> u64{ BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) } } From bfdf78e50cc22a64cfb30584d6ed3e4245c89c26 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Sat, 30 Nov 2024 16:12:44 +0000 Subject: [PATCH 11/69] Revert "build fix" This reverts commit 84551a9109d4ba4e182fadc89c5af6a4a92d4041. --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 2 +- rs/ledger_suite/icrc1/ledger/src/lib.rs | 8 ++++---- rs/ledger_suite/icrc1/ledger/src/main.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index a85c3146b58..f99196d8c27 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -43,7 +43,7 @@ pub fn icrc1_transfer( fn assert_has_num_balances(num_balances: u32) { Access::with_ledger(|ledger| { - assert_eq!(ledger.balances_len() as u32, num_balances); + assert_eq!(ledger.balances().store.len() as u32, num_balances); }); } diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 3e450ffba93..c519882153f 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -749,10 +749,6 @@ impl Ledger { pub fn copy_token_pool(&mut self) { self.stable_balances.token_pool = self.balances.token_pool; } - - pub fn balances_len(&self) -> u64{ - BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) - } } impl LedgerContext for Ledger { @@ -1186,6 +1182,10 @@ pub fn clear_stable_balances_data() { }); } +pub fn balances_len() -> u64 { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) +} + #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 106b3f88fac..21cdfe1c34d 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -16,7 +16,7 @@ use ic_icrc1::{ Operation, Transaction, }; use ic_icrc1_ledger::{ - clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, + balances_len, clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, LEDGER_VERSION, UPGRADES_MEMORY, }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; @@ -419,7 +419,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - ledger.balances_len() as f64, + balances_len() as f64, "Total number of accounts in the balance store.", )?; } From 2749fe0eddcf66304ba9db12d244c519d9f053d4 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Sat, 30 Nov 2024 16:12:53 +0000 Subject: [PATCH 12/69] Revert "clippy" This reverts commit 996abf8d647f39e2d2dd8fb820d9b5f17906991c. --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index c519882153f..b8bcc347859 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -748,7 +748,7 @@ impl Ledger { pub fn copy_token_pool(&mut self) { self.stable_balances.token_pool = self.balances.token_pool; - } + } } impl LedgerContext for Ledger { From 40062fc0f80b7614f64064c4c701a5b4e0a4de86 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Sat, 30 Nov 2024 16:13:05 +0000 Subject: [PATCH 13/69] Revert "remove account trimming" This reverts commit 17135dd0ee03047dca82ccb291d9737b8f4aa5ae. --- .../common/ledger_canister_core/src/ledger.rs | 116 +++++++++++++++++- .../common/ledger_core/src/balances.rs | 21 ++++ rs/ledger_suite/icp/ledger/src/tests.rs | 65 ++++++++++ rs/ledger_suite/icp/ledger/tests/tests.rs | 5 + rs/ledger_suite/icrc1/ledger/src/lib.rs | 8 -- rs/ledger_suite/icrc1/ledger/src/main.rs | 13 +- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 5 + rs/ledger_suite/tests/sm-tests/src/lib.rs | 45 +++++++ 8 files changed, 262 insertions(+), 16 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index e20c09c7409..08ee45f7605 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -4,18 +4,22 @@ use ic_canister_log::{log, Sink}; use ic_ledger_core::approvals::{ AllowanceTable, AllowancesData, ApproveError, InsufficientAllowance, }; +use ic_ledger_core::tokens::Zero; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, VecDeque}; use std::ops::Range; use std::time::Duration; use crate::archive::{ArchivingGuardError, FailedToArchiveBlocks, LedgerArchivingGuard}; -use ic_ledger_core::balances::{BalanceError, Balances, BalancesStore}; +use ic_ledger_core::balances::{BalanceError, Balances, BalancesStore, InspectableBalancesStore}; use ic_ledger_core::block::{BlockIndex, BlockType, EncodedBlock, FeeCollector}; use ic_ledger_core::timestamp::TimeStamp; use ic_ledger_core::tokens::TokensType; use ic_ledger_hash_of::HashOf; +/// The memo to use for balances burned and approvals reset to 0 during trimming +const TRIMMED_MEMO: u64 = u64::MAX; + #[derive(Debug, Deserialize, Serialize)] pub struct TransactionInfo { pub block_timestamp: TimeStamp, @@ -212,6 +216,7 @@ pub fn apply_transaction( ) -> Result<(BlockIndex, HashOf), TransferError> where L: LedgerData, + L::BalancesStore: InspectableBalancesStore, { let num_pruned = purge_old_transactions(ledger, now); @@ -296,6 +301,82 @@ where transaction_hash: tx_hash, }); } + let effective_max_number_of_accounts = + ledger.max_number_of_accounts() + ledger.accounts_overflow_trim_quantity() - 1; + + let to_trim = if ledger.balances().store.len() > effective_max_number_of_accounts { + select_accounts_to_trim(ledger) + } else { + vec![] + }; + + for (balance, account) in to_trim { + let burn_tx = L::Transaction::burn(account, None, balance, Some(now), Some(TRIMMED_MEMO)); + + burn_tx + .apply(ledger, now, L::Tokens::zero()) + .expect("failed to burn funds that must have existed"); + + let parent_hash = ledger.blockchain().last_hash; + let fee_collector = ledger.fee_collector().cloned(); + + ledger + .blockchain_mut() + .add_block(L::Block::from_transaction( + parent_hash, + burn_tx, + now, + L::Tokens::zero(), + fee_collector, + )) + .unwrap(); + } + + // We estimate that an approval takes up twice as much space as a balance: + // balance = account + num_tokens + // approval = 2 * account + num_tokens + timestamp + let max_number_of_approvals = + (effective_max_number_of_accounts - ledger.balances().store.len()) / 2; + + if ledger.approvals().len() > max_number_of_approvals { + let num_approvals_to_trim = ledger.approvals().len() - max_number_of_approvals; + // There might be some more expired approvals to prune. + ledger.approvals_mut().prune(now, num_approvals_to_trim); + + if ledger.approvals().len() > max_number_of_approvals { + let approvals_to_trim = ledger + .approvals() + .select_approvals_to_trim(ledger.approvals().len() - max_number_of_approvals); + + for approval in approvals_to_trim { + let approve_tx = L::Transaction::approve( + approval.0, + approval.1, + L::Tokens::zero(), + Some(now), + Some(TRIMMED_MEMO), + ); + + approve_tx + .apply(ledger, now, L::Tokens::zero()) + .expect("failed to reset approval to zero"); + + let parent_hash = ledger.blockchain().last_hash; + let fee_collector = ledger.fee_collector().cloned(); + + ledger + .blockchain_mut() + .add_block(L::Block::from_transaction( + parent_hash, + approve_tx, + now, + L::Tokens::zero(), + fee_collector, + )) + .unwrap(); + } + } + } Ok((height, ledger.blockchain().last_hash.unwrap())) } @@ -393,6 +474,39 @@ pub fn purge_old_transactions(ledger: &mut L, now: TimeStamp) -> num_tx_purged } +// Find the specified number of accounts with lowest balances so that their +// balances can be reclaimed. +fn select_accounts_to_trim(ledger: &L) -> Vec<(L::Tokens, L::AccountId)> +where + L: LedgerData, + L::BalancesStore: InspectableBalancesStore, + L::Tokens: TokensType, +{ + let mut to_trim: std::collections::BinaryHeap<(L::Tokens, L::AccountId)> = + std::collections::BinaryHeap::new(); + + let num_accounts = ledger.accounts_overflow_trim_quantity(); + let mut iter = ledger.balances().store.iter(); + + // Accumulate up to `trim_quantity` accounts + for (account, balance) in iter.by_ref().take(num_accounts) { + to_trim.push((balance.clone(), account.clone())); + } + + for (account, balance) in iter { + // If any account's balance is lower than the maximum in our set, + // include that account, and remove the current maximum + if let Some((greatest_balance, _)) = to_trim.peek() { + if balance < greatest_balance { + to_trim.push((balance.clone(), account.clone())); + to_trim.pop(); + } + } + } + + to_trim.into_vec() +} + /// Asynchronously archives a suffix of the locally available blockchain. /// /// NOTE: only one archiving task can run at each point in time. diff --git a/rs/ledger_suite/common/ledger_core/src/balances.rs b/rs/ledger_suite/common/ledger_core/src/balances.rs index cd229dfcabe..68d9791b879 100644 --- a/rs/ledger_suite/common/ledger_core/src/balances.rs +++ b/rs/ledger_suite/common/ledger_core/src/balances.rs @@ -19,6 +19,13 @@ pub trait BalancesStore { F: FnMut(Option<&Self::Tokens>) -> Result; } +#[allow(clippy::len_without_is_empty)] +pub trait InspectableBalancesStore: BalancesStore { + fn iter(&self) -> Box + '_>; + + fn len(&self) -> usize; +} + impl BalancesStore for BTreeMap where AccountId: Eq + Clone + std::cmp::Ord, @@ -56,6 +63,20 @@ where } } +impl InspectableBalancesStore for BTreeMap +where + AccountId: Eq + Clone + std::cmp::Ord, + Tokens: TokensType, +{ + fn len(&self) -> usize { + self.len() + } + + fn iter(&self) -> Box + '_> { + Box::new(self.iter()) + } +} + /// An error returned by `Balances` if the debit operation fails. #[derive(Debug)] pub enum BalanceError { diff --git a/rs/ledger_suite/icp/ledger/src/tests.rs b/rs/ledger_suite/icp/ledger/src/tests.rs index 42e0dedd66f..d4838e9ce4e 100644 --- a/rs/ledger_suite/icp/ledger/src/tests.rs +++ b/rs/ledger_suite/icp/ledger/src/tests.rs @@ -31,6 +31,71 @@ fn ts(n: u64) -> TimeStamp { TimeStamp::from_nanos_since_unix_epoch(n) } +#[test] +fn balances_overflow() { + let balances = LedgerBalances::new(); + let mut state = Ledger { + balances, + maximum_number_of_accounts: 8, + accounts_overflow_trim_quantity: 2, + minting_account_id: Some(PrincipalId::new_user_test_id(137).into()), + ..Default::default() + }; + assert_eq!(state.balances.token_pool, Tokens::MAX); + println!( + "minting canister initial balance: {}", + state.balances.token_pool + ); + let mut credited = Tokens::ZERO; + + // 11 accounts. The one with 0 will not be added + // The rest will be added and trigger a trim of 2 once + // the total number reaches 8 + 2 + // the number of active accounts won't go below 8 after trimming + for i in 0..11 { + let amount = Tokens::new(i, 0).unwrap(); + state + .add_payment( + Memo::default(), + Operation::Mint { + to: PrincipalId::new_user_test_id(i).into(), + amount, + }, + None, + ) + .unwrap(); + credited = credited.checked_add(&amount).unwrap(); + } + println!("amount credited to accounts: {}", credited); + + println!("balances: {:?}", state.balances); + + // The two accounts with lowest balances, 0 and 1 respectively, have been + // removed + assert_eq!(state.balances.store.len(), 8); + assert_eq!( + state + .balances + .account_balance(&PrincipalId::new_user_test_id(0).into()), + Tokens::ZERO + ); + assert_eq!( + state + .balances + .account_balance(&PrincipalId::new_user_test_id(1).into()), + Tokens::ZERO + ); + // We have credited 55 Tokens to various accounts but the three accounts + // with lowest balances, 0, 1 and 2, should have been removed and their + // balance returned to the minting canister + let expected_minting_canister_balance = Tokens::MAX + .checked_sub(&credited) + .unwrap() + .checked_add(&Tokens::new(1 + 2, 0).unwrap()) + .unwrap(); + assert_eq!(state.balances.token_pool, expected_minting_canister_balance); +} + #[test] fn balances_remove_accounts_with_zero_balance() { let mut ctx = Ledger::default(); diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 7112784618b..94db23d807e 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1502,6 +1502,11 @@ fn test_transfer_from_burn() { ic_ledger_suite_state_machine_tests::test_transfer_from_burn(ledger_wasm(), encode_init_args); } +#[test] +fn test_balances_overflow() { + ic_ledger_suite_state_machine_tests::test_balances_overflow(ledger_wasm(), encode_init_args); +} + #[test] fn test_approval_trimming() { ic_ledger_suite_state_machine_tests::test_approval_trimming( diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index b8bcc347859..622e13d6a6d 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -745,10 +745,6 @@ impl Ledger { pub fn clear_arrivals(&mut self) { self.approvals.allowances_data.clear_arrivals(); } - - pub fn copy_token_pool(&mut self) { - self.stable_balances.token_pool = self.balances.token_pool; - } } impl LedgerContext for Ledger { @@ -1182,10 +1178,6 @@ pub fn clear_stable_balances_data() { }); } -pub fn balances_len() -> u64 { - BALANCES_MEMORY.with_borrow_mut(|balances| balances.len()) -} - #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 21cdfe1c34d..24b54fb30ca 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -16,8 +16,8 @@ use ic_icrc1::{ Operation, Transaction, }; use ic_icrc1_ledger::{ - balances_len, clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, - panic_if_not_ready, set_ledger_state, LEDGER_VERSION, UPGRADES_MEMORY, + clear_stable_allowance_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, + LEDGER_VERSION, UPGRADES_MEMORY, }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; use ic_ledger_canister_core::ledger::{ @@ -241,9 +241,6 @@ fn post_upgrade(args: Option) { set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); log_message("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data."); clear_stable_balances_data(); - Access::with_ledger_mut(|ledger| { - ledger.copy_token_pool(); - }); } if upgrade_from_version == 0 { set_ledger_state(LedgerState::Migrating(LedgerField::Allowances)); @@ -294,7 +291,9 @@ fn migrate_next_part(instruction_limit: u64) { if ledger.migrate_one_expiration() { migrated_expirations += 1; } else { - set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); + set_ledger_state(LedgerState::Migrating( + LedgerField::Balances, + )); } } LedgerField::Balances => { @@ -419,7 +418,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - balances_len() as f64, + ledger.balances().store.len() as f64, "Total number of accounts in the balance store.", )?; } diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index cd7d0ce58a0..a098a08da8b 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -390,6 +390,11 @@ fn test_transfer_from_burn() { ic_ledger_suite_state_machine_tests::test_transfer_from_burn(ledger_wasm(), encode_init_args); } +#[test] +fn test_balances_overflow() { + ic_ledger_suite_state_machine_tests::test_balances_overflow(ledger_wasm(), encode_init_args); +} + #[test] fn test_approval_trimming() { ic_ledger_suite_state_machine_tests::test_approval_trimming( diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index c1bff467889..71c412e9af3 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3822,6 +3822,51 @@ where assert_eq!(total_supply(&env, canister_id), 60_000); } +pub fn test_balances_overflow(ledger_wasm: Vec, encode_init_args: fn(InitArgs) -> T) +where + T: CandidType, +{ + let env = StateMachine::new(); + + let args = encode_init_args(InitArgs { + maximum_number_of_accounts: Some(8), + accounts_overflow_trim_quantity: Some(2), + ..init_args(vec![]) + }); + let args = Encode!(&args).unwrap(); + let canister_id = env.install_canister(ledger_wasm, args, None).unwrap(); + + let minter = minting_account(&env, canister_id).unwrap(); + + let mut credited = 0; + for i in 0..11 { + transfer( + &env, + canister_id, + minter, + PrincipalId::new_user_test_id(i).0, + i, + ) + .expect("failed to mint tokens"); + credited += i; + } + assert_eq!( + balance_of(&env, canister_id, PrincipalId::new_user_test_id(1).0), + 0 + ); + assert_eq!( + balance_of(&env, canister_id, PrincipalId::new_user_test_id(2).0), + 0 + ); + for i in 3..11 { + assert_eq!( + balance_of(&env, canister_id, PrincipalId::new_user_test_id(i).0), + i + ); + } + assert_eq!(total_supply(&env, canister_id), credited - 1 - 2); +} + pub fn test_approval_trimming( ledger_wasm: Vec, encode_init_args: fn(InitArgs) -> T, From fccd63139bf54c06f40de41339dead901235c84b Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 12:00:01 +0000 Subject: [PATCH 14/69] disable balance/approval pruning for icrc ledger --- .../common/ledger_canister_core/src/ledger.rs | 27 +++++++++++++++++-- .../icrc1/ledger/src/benches/mod.rs | 2 +- rs/ledger_suite/icrc1/ledger/src/lib.rs | 26 +++++++++++++----- rs/ledger_suite/icrc1/ledger/src/main.rs | 19 ++++++------- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 5 ---- 5 files changed, 55 insertions(+), 24 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index 08ee45f7605..33a31fe41cc 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -217,6 +217,21 @@ pub fn apply_transaction( where L: LedgerData, L::BalancesStore: InspectableBalancesStore, +{ + let result = apply_transaction_no_prunning(ledger, transaction, now, effective_fee); + prune_balances_and_allowances(ledger, now); + result +} + +/// Adds a new block with the specified transaction to the ledger. +pub fn apply_transaction_no_prunning( + ledger: &mut L, + transaction: L::Transaction, + now: TimeStamp, + effective_fee: L::Tokens, +) -> Result<(BlockIndex, HashOf), TransferError> +where + L: LedgerData, { let num_pruned = purge_old_transactions(ledger, now); @@ -301,6 +316,16 @@ where transaction_hash: tx_hash, }); } + + Ok((height, ledger.blockchain().last_hash.unwrap())) +} + +/// Adds a new block with the specified transaction to the ledger. +fn prune_balances_and_allowances(ledger: &mut L, now: TimeStamp) +where + L: LedgerData, + L::BalancesStore: InspectableBalancesStore, +{ let effective_max_number_of_accounts = ledger.max_number_of_accounts() + ledger.accounts_overflow_trim_quantity() - 1; @@ -377,8 +402,6 @@ where } } } - - Ok((height, ledger.blockchain().last_hash.unwrap())) } /// Finds the archive canister that contains the block with the specified height. diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index f99196d8c27..a85c3146b58 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -43,7 +43,7 @@ pub fn icrc1_transfer( fn assert_has_num_balances(num_balances: u32) { Access::with_ledger(|ledger| { - assert_eq!(ledger.balances().store.len() as u32, num_balances); + assert_eq!(ledger.balances_len() as u32, num_balances); }); } diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 622e13d6a6d..65ac1ed4061 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -22,7 +22,9 @@ use ic_ledger_canister_core::runtime::Runtime; use ic_ledger_canister_core::{ archive::ArchiveCanisterWasm, blockchain::Blockchain, - ledger::{apply_transaction, block_locations, LedgerContext, LedgerData, TransactionInfo}, + ledger::{ + apply_transaction_no_prunning, block_locations, LedgerContext, LedgerData, TransactionInfo, + }, range_utils, }; use ic_ledger_core::balances::BalancesStore; @@ -697,12 +699,14 @@ impl Ledger { ) }); let mint = Transaction::mint(account, amount, Some(now), None); - apply_transaction(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else(|err| { - panic!( - "failed to mint {} tokens to {}: {:?}", - balance, account, err - ) - }); + apply_transaction_no_prunning(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else( + |err| { + panic!( + "failed to mint {} tokens to {}: {:?}", + balance, account, err + ) + }, + ); } ledger @@ -745,6 +749,14 @@ impl Ledger { pub fn clear_arrivals(&mut self) { self.approvals.allowances_data.clear_arrivals(); } + + pub fn copy_token_pool(&mut self) { + self.stable_balances.token_pool = self.balances.token_pool; + } + + pub fn balances_len(&self) -> u64 { + BALANCES_MEMORY.with_borrow(|balances| balances.len()) + } } impl LedgerContext for Ledger { diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 24b54fb30ca..672230a2b0b 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -16,12 +16,12 @@ use ic_icrc1::{ Operation, Transaction, }; use ic_icrc1_ledger::{ - clear_stable_allowance_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, - LEDGER_VERSION, UPGRADES_MEMORY, + clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, + panic_if_not_ready, set_ledger_state, LEDGER_VERSION, UPGRADES_MEMORY, }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; use ic_ledger_canister_core::ledger::{ - apply_transaction, archive_blocks, LedgerAccess, LedgerContext, LedgerData, + apply_transaction_no_prunning, archive_blocks, LedgerAccess, LedgerContext, LedgerData, TransferError as CoreTransferError, }; use ic_ledger_canister_core::runtime::heap_memory_size_bytes; @@ -241,6 +241,9 @@ fn post_upgrade(args: Option) { set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); log_message("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data."); clear_stable_balances_data(); + Access::with_ledger_mut(|ledger| { + ledger.copy_token_pool(); + }); } if upgrade_from_version == 0 { set_ledger_state(LedgerState::Migrating(LedgerField::Allowances)); @@ -291,9 +294,7 @@ fn migrate_next_part(instruction_limit: u64) { if ledger.migrate_one_expiration() { migrated_expirations += 1; } else { - set_ledger_state(LedgerState::Migrating( - LedgerField::Balances, - )); + set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); } } LedgerField::Balances => { @@ -418,7 +419,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - ledger.balances().store.len() as f64, + ledger.balances_len() as f64, "Total number of accounts in the balance store.", )?; } @@ -668,7 +669,7 @@ fn execute_transfer_not_async( ) }; - let (block_idx, _) = apply_transaction(ledger, tx, now, effective_fee)?; + let (block_idx, _) = apply_transaction_no_prunning(ledger, tx, now, effective_fee)?; Ok(block_idx) }) } @@ -867,7 +868,7 @@ async fn icrc2_approve(arg: ApproveArgs) -> Result { memo: arg.memo, }; - let (block_idx, _) = apply_transaction(ledger, tx, now, expected_fee_tokens) + let (block_idx, _) = apply_transaction_no_prunning(ledger, tx, now, expected_fee_tokens) .map_err(convert_transfer_error) .map_err(|err| { let err: ApproveError = match err.try_into() { diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index a098a08da8b..cd7d0ce58a0 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -390,11 +390,6 @@ fn test_transfer_from_burn() { ic_ledger_suite_state_machine_tests::test_transfer_from_burn(ledger_wasm(), encode_init_args); } -#[test] -fn test_balances_overflow() { - ic_ledger_suite_state_machine_tests::test_balances_overflow(ledger_wasm(), encode_init_args); -} - #[test] fn test_approval_trimming() { ic_ledger_suite_state_machine_tests::test_approval_trimming( From c9d957e62d3bea3b8dcee2468071446036ccc53e Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 12:07:26 +0000 Subject: [PATCH 15/69] fix comments --- rs/ledger_suite/common/ledger_canister_core/src/ledger.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index 33a31fe41cc..e328904e4e2 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -208,6 +208,7 @@ pub enum TransferError { const APPROVE_PRUNE_LIMIT: usize = 100; /// Adds a new block with the specified transaction to the ledger. +/// Prune balances and allowances if necessary. pub fn apply_transaction( ledger: &mut L, transaction: L::Transaction, @@ -224,6 +225,7 @@ where } /// Adds a new block with the specified transaction to the ledger. +/// Do not perform any balance or allowance prunning. pub fn apply_transaction_no_prunning( ledger: &mut L, transaction: L::Transaction, @@ -320,7 +322,8 @@ where Ok((height, ledger.blockchain().last_hash.unwrap())) } -/// Adds a new block with the specified transaction to the ledger. +/// Prune balances and allowances. Can be used e.g. if the ledger +/// is low on heap memory. fn prune_balances_and_allowances(ledger: &mut L, now: TimeStamp) where L: LedgerData, From d729ebeb668b81733429edf201754e5ae499bbb7 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 12:12:42 +0000 Subject: [PATCH 16/69] clippy --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 4 +--- rs/ledger_suite/icrc1/ledger/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index a85c3146b58..d05c743c304 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -2,9 +2,7 @@ use crate::{execute_transfer_not_async, post_upgrade, pre_upgrade, Access, Token use assert_matches::assert_matches; use candid::{Nat, Principal}; use ic_canister_log::Sink; -use ic_ledger_canister_core::ledger::{ - blocks_to_archive, remove_archived_blocks, LedgerAccess, LedgerContext, -}; +use ic_ledger_canister_core::ledger::{blocks_to_archive, remove_archived_blocks, LedgerAccess}; use ic_ledger_core::block::BlockIndex; use icrc_ledger_types::icrc1::account::Account; use icrc_ledger_types::icrc1::transfer::TransferArg; diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 672230a2b0b..a8d226d1346 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -307,7 +307,7 @@ fn migrate_next_part(instruction_limit: u64) { } } let instructions_migration = instruction_counter() - instructions_migration_start; - let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations} balances {migrated_balances}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , + let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations} balances: {migrated_balances}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , instruction_counter()); if !is_ready() { log_message( From e3bb73f9e84d0885380fbbf0caa97176fc1bcc63 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 12:35:11 +0000 Subject: [PATCH 17/69] balances_len not a member fn --- rs/ledger_suite/icrc1/ledger/src/benches/mod.rs | 6 ++---- rs/ledger_suite/icrc1/ledger/src/lib.rs | 8 ++++---- rs/ledger_suite/icrc1/ledger/src/main.rs | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs index d05c743c304..68d36334239 100644 --- a/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs +++ b/rs/ledger_suite/icrc1/ledger/src/benches/mod.rs @@ -1,4 +1,4 @@ -use crate::{execute_transfer_not_async, post_upgrade, pre_upgrade, Access, Tokens}; +use crate::{balances_len, execute_transfer_not_async, post_upgrade, pre_upgrade, Tokens}; use assert_matches::assert_matches; use candid::{Nat, Principal}; use ic_canister_log::Sink; @@ -40,9 +40,7 @@ pub fn icrc1_transfer( } fn assert_has_num_balances(num_balances: u32) { - Access::with_ledger(|ledger| { - assert_eq!(ledger.balances_len() as u32, num_balances); - }); + assert_eq!(balances_len() as u32, num_balances); } pub fn max_length_principal(index: u32) -> Principal { diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 65ac1ed4061..a0837682dd9 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -753,10 +753,6 @@ impl Ledger { pub fn copy_token_pool(&mut self) { self.stable_balances.token_pool = self.balances.token_pool; } - - pub fn balances_len(&self) -> u64 { - BALANCES_MEMORY.with_borrow(|balances| balances.len()) - } } impl LedgerContext for Ledger { @@ -1190,6 +1186,10 @@ pub fn clear_stable_balances_data() { }); } +pub fn balances_len() -> u64 { + BALANCES_MEMORY.with_borrow(|balances| balances.len()) +} + #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index a8d226d1346..bb99cbd9878 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -16,7 +16,7 @@ use ic_icrc1::{ Operation, Transaction, }; use ic_icrc1_ledger::{ - clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, + balances_len, clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, LEDGER_VERSION, UPGRADES_MEMORY, }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; @@ -419,7 +419,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - ledger.balances_len() as f64, + balances_len() as f64, "Total number of accounts in the balance store.", )?; } From 0dca3a4ccc0eef27ead04041a64207de3e93e92e Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 13:03:37 +0000 Subject: [PATCH 18/69] update canbench results --- .../ledger/canbench_results/canbench_u256.yml | 32 +++++++++---------- .../ledger/canbench_results/canbench_u64.yml | 32 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u256.yml b/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u256.yml index 77770b0cfb7..4fe24655c4a 100644 --- a/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u256.yml +++ b/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u256.yml @@ -1,42 +1,42 @@ benches: bench_icrc1_transfers: total: - instructions: 6398923208 - heap_increase: 227 + instructions: 13798815361 + heap_increase: 172 stable_memory_increase: 128 scopes: before_upgrade: - instructions: 5790054103 - heap_increase: 71 + instructions: 13630531777 + heap_increase: 43 stable_memory_increase: 0 post_upgrade: - instructions: 424320009 - heap_increase: 27 + instructions: 118601062 + heap_increase: 0 stable_memory_increase: 0 pre_upgrade: - instructions: 184546072 + instructions: 49679478 heap_increase: 129 stable_memory_increase: 128 upgrade: - instructions: 608867671 - heap_increase: 156 + instructions: 168282130 + heap_increase: 129 stable_memory_increase: 128 bench_upgrade_baseline: total: - instructions: 8755062 + instructions: 8684974 heap_increase: 258 - stable_memory_increase: 129 + stable_memory_increase: 128 scopes: post_upgrade: - instructions: 8627524 + instructions: 8606422 heap_increase: 129 stable_memory_increase: 0 pre_upgrade: - instructions: 125131 + instructions: 76145 heap_increase: 129 - stable_memory_increase: 129 + stable_memory_increase: 128 upgrade: - instructions: 8754373 + instructions: 8684285 heap_increase: 258 - stable_memory_increase: 129 + stable_memory_increase: 128 version: 0.1.7 diff --git a/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u64.yml b/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u64.yml index 22fe755925c..7e7164f34e5 100644 --- a/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u64.yml +++ b/rs/ledger_suite/icrc1/ledger/canbench_results/canbench_u64.yml @@ -1,42 +1,42 @@ benches: bench_icrc1_transfers: total: - instructions: 5926738616 - heap_increase: 214 + instructions: 13237283790 + heap_increase: 171 stable_memory_increase: 128 scopes: before_upgrade: - instructions: 5341274673 - heap_increase: 64 + instructions: 13068913917 + heap_increase: 42 stable_memory_increase: 0 post_upgrade: - instructions: 406888378 - heap_increase: 21 + instructions: 118797275 + heap_increase: 0 stable_memory_increase: 0 pre_upgrade: - instructions: 178572258 + instructions: 49569466 heap_increase: 129 stable_memory_increase: 128 upgrade: - instructions: 585462226 - heap_increase: 150 + instructions: 168368331 + heap_increase: 129 stable_memory_increase: 128 bench_upgrade_baseline: total: - instructions: 8758206 + instructions: 8686052 heap_increase: 258 - stable_memory_increase: 129 + stable_memory_increase: 128 scopes: post_upgrade: - instructions: 8627876 + instructions: 8606533 heap_increase: 129 stable_memory_increase: 0 pre_upgrade: - instructions: 127923 + instructions: 77112 heap_increase: 129 - stable_memory_increase: 129 + stable_memory_increase: 128 upgrade: - instructions: 8757517 + instructions: 8685363 heap_increase: 258 - stable_memory_increase: 129 + stable_memory_increase: 128 version: 0.1.7 From 362bc8ad7167cf7c98604bcdcbb82e73ddce2da8 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 15:56:49 +0000 Subject: [PATCH 19/69] update mainnet u64 wasm, add v1 and v2 wasms --- mainnet-canisters.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mainnet-canisters.json b/mainnet-canisters.json index e84a6b131e3..72e60289c2b 100644 --- a/mainnet-canisters.json +++ b/mainnet-canisters.json @@ -12,6 +12,14 @@ "sha256": "67b5f0bf128e801adf4a959ea26c3c9ca0cd399940e169a26a2eb237899a94dd" }, "ck_btc_ledger": { + "rev": "8d726cc67a8ec83b55e5dc6305f49c1e4304d6dd", + "sha256": "d12febb9b719c2bbf44e18bccc9fd027a1d2e823622d0dc8b524c8a43bd4f698" + }, + "ck_btc_ledger_v1": { + "rev": "d4ee25b0865e89d3eaac13a60f0016d5e3296b31", + "sha256": "a170bfdce5d66e751a3cc03747cb0f06b450af500e75e15976ec08a3f5691f4c" + }, + "ck_btc_ledger_v2": { "rev": "e54d3fa34ded227c885d04e64505fa4b5d564743", "sha256": "3d808fa63a3d8ebd4510c0400aa078e99a31afaa0515f0b68778f929ce4b2a46" }, From b528d1fa256d9e571c5eb3ee7cc88e1ab217fc49 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 2 Dec 2024 16:07:12 +0000 Subject: [PATCH 20/69] add v1 and v2 to bazel --- WORKSPACE.bazel | 4 ++++ rs/ledger_suite/icrc1/ledger/BUILD.bazel | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 3cabb35ab87..272afb2018c 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -26,6 +26,8 @@ canisters( "sns-wasm": "sns-wasm-canister.wasm.gz", "ck_btc_archive": "ic-icrc1-archive.wasm.gz", "ck_btc_ledger": "ic-icrc1-ledger.wasm.gz", + "ck_btc_ledger_v1": "ic-icrc1-ledger.wasm.gz", + "ck_btc_ledger_v2": "ic-icrc1-ledger.wasm.gz", "ck_btc_index": "ic-icrc1-index-ng.wasm.gz", "ck_eth_archive": "ic-icrc1-archive-u256.wasm.gz", "ck_eth_ledger": "ic-icrc1-ledger-u256.wasm.gz", @@ -52,6 +54,8 @@ canisters( "sns-wasm": "mainnet_nns_sns-wasm-canister", "ck_btc_archive": "mainnet_ckbtc_ic-icrc1-archive", "ck_btc_ledger": "mainnet_ckbtc_ic-icrc1-ledger", + "ck_btc_ledger_v1": "mainnet_ckbtc_ic-icrc1-ledger-v1", + "ck_btc_ledger_v2": "mainnet_ckbtc_ic-icrc1-ledger-v2", "ck_btc_index": "mainnet_ckbtc-index-ng", "ck_eth_archive": "mainnet_cketh_ic-icrc1-archive-u256", "ck_eth_ledger": "mainnet_cketh_ic-icrc1-ledger-u256", diff --git a/rs/ledger_suite/icrc1/ledger/BUILD.bazel b/rs/ledger_suite/icrc1/ledger/BUILD.bazel index 3a283db1377..3ed7c826f2a 100644 --- a/rs/ledger_suite/icrc1/ledger/BUILD.bazel +++ b/rs/ledger_suite/icrc1/ledger/BUILD.bazel @@ -278,6 +278,8 @@ rust_test( "//rs/ledger_suite/icrc1/archive:archive_canister" + name_suffix + ".wasm.gz", "//rs/ledger_suite/icrc1/ledger:ledger_canister_icrc3_compatible_data_certificate", "//rs/universal_canister/impl:universal_canister.wasm.gz", + "@mainnet_ckbtc_ic-icrc1-ledger-v1//file", + "@mainnet_ckbtc_ic-icrc1-ledger-v2//file", "@mainnet_ckbtc_ic-icrc1-ledger//file", "@mainnet_cketh_ic-icrc1-ledger-u256//file", "@mainnet_ic-icrc1-ledger//file", @@ -285,6 +287,8 @@ rust_test( env = { "CARGO_MANIFEST_DIR": "rs/ledger_suite/icrc1/ledger", "CKBTC_IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger//file)", + "CKBTC_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-v1//file)", + "CKBTC_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-v2//file)", "CKETH_IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH": "$(rootpath @mainnet_cketh_ic-icrc1-ledger-u256//file)", "IC_ICRC1_ARCHIVE_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/archive:archive_canister" + name_suffix + ".wasm.gz)", "IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH": "$(rootpath @mainnet_ic-icrc1-ledger//file)", From 263459676e413386ea81e214ca4e84ed87d90863 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 11:13:41 +0000 Subject: [PATCH 21/69] add v2 and mainnet testing to some tests --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 97 +++++++++++++++++++-- rs/ledger_suite/tests/sm-tests/src/lib.rs | 52 +++++++++-- 2 files changed, 139 insertions(+), 10 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index cd7d0ce58a0..3a298885cb3 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -77,16 +77,48 @@ fn ledger_mainnet_wasm() -> Vec { mainnet_wasm } +fn ledger_mainnet_v2_wasm() -> Vec { + #[cfg(not(feature = "u256-tokens"))] + let mainnet_wasm = ledger_mainnet_v2_u64_wasm(); + #[cfg(feature = "u256-tokens")] + let mainnet_wasm = ledger_mainnet_v2_u256_wasm(); + mainnet_wasm +} + +fn ledger_mainnet_v1_wasm() -> Vec { + #[cfg(not(feature = "u256-tokens"))] + let mainnet_wasm = ledger_mainnet_v1_u64_wasm(); + #[cfg(feature = "u256-tokens")] + let mainnet_wasm = ledger_mainnet_v1_u256_wasm(); + mainnet_wasm +} + fn ledger_mainnet_u64_wasm() -> Vec { std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH").unwrap()) .unwrap() } +fn ledger_mainnet_v2_u64_wasm() -> Vec { + std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH").unwrap()).unwrap() +} + +fn ledger_mainnet_v1_u64_wasm() -> Vec { + std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH").unwrap()).unwrap() +} + fn ledger_mainnet_u256_wasm() -> Vec { std::fs::read(std::env::var("CKETH_IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH").unwrap()) .unwrap() } +fn ledger_mainnet_v2_u256_wasm() -> Vec { + std::fs::read(std::env::var("CKETH_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH").unwrap()).unwrap() +} + +fn ledger_mainnet_v1_u256_wasm() -> Vec { + std::fs::read(std::env::var("CKETH_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH").unwrap()).unwrap() +} + fn ledger_wasm() -> Vec { ic_test_utilities_load_wasm::load_wasm( std::env::var("CARGO_MANIFEST_DIR").unwrap(), @@ -442,7 +474,7 @@ fn test_block_transformation() { } #[test] -fn icrc1_test_upgrade_serialization() { +fn icrc1_test_upgrade_serialization_from_mainnet() { let minter = Arc::new(minter_identity()); let builder = LedgerInitArgsBuilder::with_symbol_and_name(TOKEN_SYMBOL, TOKEN_NAME) .with_minting_account(minter.sender().unwrap()) @@ -461,7 +493,26 @@ fn icrc1_test_upgrade_serialization() { } #[test] -fn icrc1_test_multi_step_migration() { +fn icrc1_test_upgrade_serialization_from_v2() { + let minter = Arc::new(minter_identity()); + let builder = LedgerInitArgsBuilder::with_symbol_and_name(TOKEN_SYMBOL, TOKEN_NAME) + .with_minting_account(minter.sender().unwrap()) + .with_transfer_fee(FEE); + let init_args = Encode!(&LedgerArgument::Init(builder.build())).unwrap(); + let upgrade_args = Encode!(&LedgerArgument::Upgrade(None)).unwrap(); + ic_ledger_suite_state_machine_tests::test_upgrade_serialization::( + ledger_mainnet_v2_wasm(), + ledger_wasm(), + init_args, + upgrade_args, + minter, + true, + true, + ); +} + +#[test] +fn icrc1_test_multi_step_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration( ledger_mainnet_wasm(), ledger_wasm_lowupgradeinstructionlimits(), @@ -469,6 +520,15 @@ fn icrc1_test_multi_step_migration() { ); } +#[test] +fn icrc1_test_multi_step_migration_from_v2() { + ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration( + ledger_mainnet_v2_wasm(), + ledger_wasm_lowupgradeinstructionlimits(), + encode_init_args, + ); +} + #[test] fn icrc1_test_downgrade_from_incompatible_version() { ic_ledger_suite_state_machine_tests::test_downgrade_from_incompatible_version( @@ -481,7 +541,7 @@ fn icrc1_test_downgrade_from_incompatible_version() { } #[test] -fn icrc1_test_stable_migration_endpoints_disabled() { +fn icrc1_test_stable_migration_endpoints_disabled_from_mainnet() { ic_ledger_suite_state_machine_tests::icrc1_test_stable_migration_endpoints_disabled( ledger_mainnet_wasm(), ledger_wasm_lowupgradeinstructionlimits(), @@ -490,7 +550,16 @@ fn icrc1_test_stable_migration_endpoints_disabled() { } #[test] -fn icrc1_test_incomplete_migration() { +fn icrc1_test_stable_migration_endpoints_disabled_from_v2() { + ic_ledger_suite_state_machine_tests::icrc1_test_stable_migration_endpoints_disabled( + ledger_mainnet_v2_wasm(), + ledger_wasm_lowupgradeinstructionlimits(), + encode_init_args, + ); +} + +#[test] +fn icrc1_test_incomplete_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::test_incomplete_migration( ledger_mainnet_wasm(), ledger_wasm_lowupgradeinstructionlimits(), @@ -498,6 +567,15 @@ fn icrc1_test_incomplete_migration() { ); } +#[test] +fn icrc1_test_incomplete_migration_from_v2() { + ic_ledger_suite_state_machine_tests::test_incomplete_migration( + ledger_mainnet_v2_wasm(), + ledger_wasm_lowupgradeinstructionlimits(), + encode_init_args, + ); +} + #[test] fn icrc1_test_incomplete_migration_to_current() { ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( @@ -517,7 +595,7 @@ fn icrc1_test_migration_resumes_from_frozen() { } #[test] -fn icrc1_test_metrics_while_migrating() { +fn icrc1_test_metrics_while_migrating_from_mainnet() { ic_ledger_suite_state_machine_tests::test_metrics_while_migrating( ledger_mainnet_wasm(), ledger_wasm_lowupgradeinstructionlimits(), @@ -525,6 +603,15 @@ fn icrc1_test_metrics_while_migrating() { ); } +#[test] +fn icrc1_test_metrics_while_migrating_from_v2() { + ic_ledger_suite_state_machine_tests::test_metrics_while_migrating( + ledger_mainnet_v2_wasm(), + ledger_wasm_lowupgradeinstructionlimits(), + encode_init_args, + ); +} + mod metrics { use crate::{encode_init_args, encode_upgrade_args, ledger_wasm}; use ic_ledger_suite_state_machine_tests::metrics::LedgerSuiteType; diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 71c412e9af3..1decfdf8fdd 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -2497,7 +2497,7 @@ pub fn icrc1_test_multi_step_migration( }, ]; let mut initial_balances = vec![]; - let all_accounts = [accounts.clone(), additional_accounts.clone()].concat(); + let mut all_accounts = [accounts.clone(), additional_accounts.clone()].concat(); for (index, account) in all_accounts.iter().enumerate() { initial_balances.push((*account, 10_000_000u64 + index as u64)); } @@ -2537,6 +2537,11 @@ pub fn icrc1_test_multi_step_migration( )); } } + for i in 7..7 + 30 { + let to = Account::from(PrincipalId::new_user_test_id(i).0); + transfer(&env, canister_id, accounts[0], to, 100).expect("failed to transfer funds"); + all_accounts.push(to); + } let mut balances = BTreeMap::new(); for account in &all_accounts { balances.insert(account, Nat::from(balance_of(&env, canister_id, *account))); @@ -2552,7 +2557,7 @@ pub fn icrc1_test_multi_step_migration( ) .unwrap(); - wait_ledger_ready(&env, canister_id, 10); + wait_ledger_ready(&env, canister_id, 20); let stable_upgrade_migration_steps = parse_metric(&env, canister_id, "ledger_stable_upgrade_migration_steps"); @@ -2720,6 +2725,11 @@ pub fn icrc1_test_stable_migration_endpoints_disabled( send_approval(&env, canister_id, account.owner, &approve_args).expect("approval failed"); } + for i in 2..30 { + let to = Account::from(PrincipalId::new_user_test_id(i).0); + transfer(&env, canister_id, account, to, 100).expect("failed to transfer funds"); + } + env.upgrade_canister( canister_id, ledger_wasm_current_lowinstructionlimits, @@ -2776,7 +2786,7 @@ pub fn icrc1_test_stable_migration_endpoints_disabled( test_endpoint("icrc1_balance_of", Encode!(&account).unwrap(), true); test_endpoint("icrc1_total_supply", Encode!().unwrap(), true); - wait_ledger_ready(&env, canister_id, 10); + wait_ledger_ready(&env, canister_id, 20); test_endpoint("icrc1_transfer", Encode!(&transfer_args).unwrap(), false); test_endpoint("icrc2_approve", Encode!(&approve_args).unwrap(), false); @@ -2808,8 +2818,10 @@ pub fn test_incomplete_migration( ); const APPROVE_AMOUNT: u64 = 150_000; + const TRANSFER_AMOUNT: u64 = 100; const NUM_APPROVALS: u64 = 20; + const NUM_TRANSFERS: u64 = 30; let send_approvals = || { for i in 2..2 + NUM_APPROVALS { @@ -2822,6 +2834,12 @@ pub fn test_incomplete_migration( send_approvals(); + for i in 2..2 + NUM_TRANSFERS { + let to = Account::from(PrincipalId::new_user_test_id(i).0); + transfer(&env, canister_id, account, to, TRANSFER_AMOUNT + FEE) + .expect("failed to transfer funds"); + } + let check_approvals = |non_zero_from: u64| { for i in 2..2 + NUM_APPROVALS { let allowance = Account::get_allowance( @@ -2838,8 +2856,23 @@ pub fn test_incomplete_migration( assert_eq!(allowance.allowance, expected_allowance); } }; - + let check_balances = |non_zero_from: u64| { + for i in 2..2 + NUM_TRANSFERS { + let balance = balance_of( + &env, + canister_id, + Account::from(PrincipalId::new_user_test_id(i).0), + ); + let expected_balance = if i < non_zero_from { + Nat::from(0u64) + } else { + Nat::from(TRANSFER_AMOUNT + FEE) + }; + assert_eq!(balance, expected_balance); + } + }; check_approvals(2); + check_balances(2); env.upgrade_canister( canister_id, @@ -2872,9 +2905,12 @@ pub fn test_incomplete_migration( let spender = Account::from(PrincipalId::new_user_test_id(i).0); let approve_args = default_approve_args(spender, 0); send_approval(&env, canister_id, account.owner, &approve_args).expect("approval failed"); + transfer(&env, canister_id, spender, account, TRANSFER_AMOUNT) + .expect("failed to transfer funds"); } check_approvals(5); + check_balances(5); env.upgrade_canister( canister_id, @@ -2885,6 +2921,7 @@ pub fn test_incomplete_migration( wait_ledger_ready(&env, canister_id, 20); check_approvals(5); + check_balances(5); } pub fn test_incomplete_migration_to_current( @@ -3090,6 +3127,11 @@ pub fn test_metrics_while_migrating( send_approval(&env, canister_id, account.owner, &approve_args).expect("approval failed"); } + for i in 2..30 { + let to = Account::from(PrincipalId::new_user_test_id(i).0); + transfer(&env, canister_id, account, to, 100).expect("failed to transfer funds"); + } + env.upgrade_canister( canister_id, ledger_wasm_current_lowinstructionlimits, @@ -3120,7 +3162,7 @@ pub fn test_metrics_while_migrating( .expect("failed to decode is_ledger_ready response"); assert!(!is_ledger_ready); - wait_ledger_ready(&env, canister_id, 10); + wait_ledger_ready(&env, canister_id, 20); let metrics = retrieve_metrics(&env, canister_id); assert!( From c5196906939d7c9d6c0e011e112269b771a88f6f Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 12:32:49 +0000 Subject: [PATCH 22/69] add test --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 11 ++++++- rs/ledger_suite/tests/sm-tests/src/lib.rs | 33 +++++++++++++++------ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index 3a298885cb3..848b7d866a6 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -577,7 +577,7 @@ fn icrc1_test_incomplete_migration_from_v2() { } #[test] -fn icrc1_test_incomplete_migration_to_current() { +fn icrc1_test_incomplete_migration_to_current_from_mainnet() { ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( ledger_mainnet_wasm(), ledger_wasm_lowupgradeinstructionlimits(), @@ -585,6 +585,15 @@ fn icrc1_test_incomplete_migration_to_current() { ); } +#[test] +fn icrc1_test_incomplete_migration_to_current_from_v2() { + ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( + ledger_mainnet_v2_wasm(), + ledger_wasm_lowupgradeinstructionlimits(), + encode_init_args, + ); +} + #[test] fn icrc1_test_migration_resumes_from_frozen() { ic_ledger_suite_state_machine_tests::test_migration_resumes_from_frozen( diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 1decfdf8fdd..15574117481 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -2942,8 +2942,10 @@ pub fn test_incomplete_migration_to_current( ); const APPROVE_AMOUNT: u64 = 150_000; + const TRANSFER_AMOUNT: u64 = 100; const NUM_APPROVALS: u64 = 20; + const NUM_TRANSFERS: u64 = 30; let send_approvals = || { for i in 2..2 + NUM_APPROVALS { @@ -2956,7 +2958,13 @@ pub fn test_incomplete_migration_to_current( send_approvals(); - let check_approvals = |non_zero_from: u64| { + for i in 2..2 + NUM_TRANSFERS { + let to = Account::from(PrincipalId::new_user_test_id(i).0); + transfer(&env, canister_id, account, to, TRANSFER_AMOUNT) + .expect("failed to transfer funds"); + } + + let check_approvals = || { for i in 2..2 + NUM_APPROVALS { let allowance = Account::get_allowance( &env, @@ -2964,16 +2972,22 @@ pub fn test_incomplete_migration_to_current( account, Account::from(PrincipalId::new_user_test_id(i).0), ); - let expected_allowance = if i < non_zero_from { - Nat::from(0u64) - } else { - Nat::from(APPROVE_AMOUNT) - }; - assert_eq!(allowance.allowance, expected_allowance); + assert_eq!(allowance.allowance, Nat::from(APPROVE_AMOUNT)); + } + }; + let check_balances = || { + for i in 2..2 + NUM_TRANSFERS { + let balance = balance_of( + &env, + canister_id, + Account::from(PrincipalId::new_user_test_id(i).0), + ); + assert_eq!(balance, Nat::from(TRANSFER_AMOUNT)); } }; - check_approvals(2); + check_approvals(); + check_balances(); env.upgrade_canister( canister_id, @@ -3000,7 +3014,8 @@ pub fn test_incomplete_migration_to_current( .unwrap(); wait_ledger_ready(&env, canister_id, 20); - check_approvals(2); + check_approvals(); + check_balances(); } pub fn test_migration_resumes_from_frozen( From a6d3efd8b65bc23aba2817b320456b72c85f4f86 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 13:15:57 +0000 Subject: [PATCH 23/69] frozen test --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 11 ++++++++++- rs/ledger_suite/tests/sm-tests/src/lib.rs | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index 848b7d866a6..f7a10a5cf59 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -595,7 +595,7 @@ fn icrc1_test_incomplete_migration_to_current_from_v2() { } #[test] -fn icrc1_test_migration_resumes_from_frozen() { +fn icrc1_test_migration_resumes_from_frozen_from_mainnet() { ic_ledger_suite_state_machine_tests::test_migration_resumes_from_frozen( ledger_mainnet_wasm(), ledger_wasm_lowupgradeinstructionlimits(), @@ -603,6 +603,15 @@ fn icrc1_test_migration_resumes_from_frozen() { ); } +#[test] +fn icrc1_test_migration_resumes_from_frozen_from_v2() { + ic_ledger_suite_state_machine_tests::test_migration_resumes_from_frozen( + ledger_mainnet_v2_wasm(), + ledger_wasm_lowupgradeinstructionlimits(), + encode_init_args, + ); +} + #[test] fn icrc1_test_metrics_while_migrating_from_mainnet() { ic_ledger_suite_state_machine_tests::test_metrics_while_migrating( diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 15574117481..f6932170a8c 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3046,7 +3046,10 @@ pub fn test_migration_resumes_from_frozen( .unwrap(); const APPROVE_AMOUNT: u64 = 150_000; + const TRANSFER_AMOUNT: u64 = 100; + const NUM_APPROVALS: u64 = 20; + const NUM_TRANSFERS: u64 = 30; let send_approvals = || { for i in 2..2 + NUM_APPROVALS { @@ -3059,6 +3062,12 @@ pub fn test_migration_resumes_from_frozen( send_approvals(); + for i in 2..2 + NUM_TRANSFERS { + let to = Account::from(PrincipalId::new_user_test_id(i).0); + transfer(&env, canister_id, account, to, TRANSFER_AMOUNT) + .expect("failed to transfer funds"); + } + let check_approvals = || { for i in 2..2 + NUM_APPROVALS { let allowance = Account::get_allowance( @@ -3070,8 +3079,19 @@ pub fn test_migration_resumes_from_frozen( assert_eq!(allowance.allowance, Nat::from(APPROVE_AMOUNT)); } }; + let check_balances = || { + for i in 2..2 + NUM_TRANSFERS { + let balance = balance_of( + &env, + canister_id, + Account::from(PrincipalId::new_user_test_id(i).0), + ); + assert_eq!(balance, Nat::from(TRANSFER_AMOUNT)); + } + }; check_approvals(); + check_balances(); env.upgrade_canister( canister_id, @@ -3117,6 +3137,7 @@ pub fn test_migration_resumes_from_frozen( assert!(!is_ledger_ready()); wait_ledger_ready(&env, canister_id, 20); check_approvals(); + check_balances(); } pub fn test_metrics_while_migrating( From c0b5b678f185454cd8fbda30b198bb63158f4b3f Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 13:53:03 +0000 Subject: [PATCH 24/69] add u256 v1 and v2 ledgers --- WORKSPACE.bazel | 4 ++++ mainnet-canisters.json | 8 ++++++++ rs/ledger_suite/icrc1/ledger/BUILD.bazel | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 272afb2018c..5294d5c1e6f 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -31,6 +31,8 @@ canisters( "ck_btc_index": "ic-icrc1-index-ng.wasm.gz", "ck_eth_archive": "ic-icrc1-archive-u256.wasm.gz", "ck_eth_ledger": "ic-icrc1-ledger-u256.wasm.gz", + "ck_eth_ledger_v1": "ic-icrc1-ledger-u256.wasm.gz", + "ck_eth_ledger_v2": "ic-icrc1-ledger-u256.wasm.gz", "ck_eth_index": "ic-icrc1-index-ng-u256.wasm.gz", "sns_root": "sns-root-canister.wasm.gz", "sns_governance": "sns-governance-canister.wasm.gz", @@ -59,6 +61,8 @@ canisters( "ck_btc_index": "mainnet_ckbtc-index-ng", "ck_eth_archive": "mainnet_cketh_ic-icrc1-archive-u256", "ck_eth_ledger": "mainnet_cketh_ic-icrc1-ledger-u256", + "ck_eth_ledger_v1": "mainnet_cketh_ic-icrc1-ledger-u256-v1", + "ck_eth_ledger_v2": "mainnet_cketh_ic-icrc1-ledger-u256-v2", "ck_eth_index": "mainnet_cketh-index-ng", "sns_root": "mainnet_sns-root-canister", "sns_governance": "mainnet_sns-governance-canister", diff --git a/mainnet-canisters.json b/mainnet-canisters.json index 72e60289c2b..e58cb31c096 100644 --- a/mainnet-canisters.json +++ b/mainnet-canisters.json @@ -32,6 +32,14 @@ "sha256": "07dd7a18d047ac41c37be9ea200dc1e0cbe4606bbc737d5dbb89f6e0a6e7450d" }, "ck_eth_ledger": { + "rev": "8d726cc67a8ec83b55e5dc6305f49c1e4304d6dd", + "sha256": "918f9cc15585f1a946f377f5c5041127b5a3261c95e6a485b0c899057ca28865" + }, + "ck_eth_ledger_v1": { + "rev": "d4ee25b0865e89d3eaac13a60f0016d5e3296b31", + "sha256": "e6072806ae22868ee09c07923d093b1b0b687dba540d22cfc1e1a5392bfcca46" + }, + "ck_eth_ledger_v2": { "rev": "e54d3fa34ded227c885d04e64505fa4b5d564743", "sha256": "98a7b7391608dc4a554d6964bad24157b6aaf890a05bbaad3fcc92033d9c7b02" }, diff --git a/rs/ledger_suite/icrc1/ledger/BUILD.bazel b/rs/ledger_suite/icrc1/ledger/BUILD.bazel index 3ed7c826f2a..3df7ea72c9b 100644 --- a/rs/ledger_suite/icrc1/ledger/BUILD.bazel +++ b/rs/ledger_suite/icrc1/ledger/BUILD.bazel @@ -282,6 +282,8 @@ rust_test( "@mainnet_ckbtc_ic-icrc1-ledger-v2//file", "@mainnet_ckbtc_ic-icrc1-ledger//file", "@mainnet_cketh_ic-icrc1-ledger-u256//file", + "@mainnet_cketh_ic-icrc1-ledger-u256-v1//file", + "@mainnet_cketh_ic-icrc1-ledger-u256-v2//file", "@mainnet_ic-icrc1-ledger//file", ], env = { @@ -290,6 +292,8 @@ rust_test( "CKBTC_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-v1//file)", "CKBTC_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-v2//file)", "CKETH_IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH": "$(rootpath @mainnet_cketh_ic-icrc1-ledger-u256//file)", + "CKETH_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH": "$(rootpath @mainnet_cketh_ic-icrc1-ledger-u256-v1//file)", + "CKETH_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH": "$(rootpath @mainnet_cketh_ic-icrc1-ledger-u256-v2//file)", "IC_ICRC1_ARCHIVE_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/archive:archive_canister" + name_suffix + ".wasm.gz)", "IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH": "$(rootpath @mainnet_ic-icrc1-ledger//file)", "IC_ICRC1_LEDGER_ICRC3_COMPATIBLE_DATA_CERTIFICATE_WASM_PATH": "$(rootpath //rs/ledger_suite/icrc1/ledger:ledger_canister_icrc3_compatible_data_certificate)", From 3aa03acc169a07bd9512bfe3f72ec60bde072bcb Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 14:15:02 +0000 Subject: [PATCH 25/69] test upgrade from v1 not possible --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 13 +++++++++++ rs/ledger_suite/tests/sm-tests/src/lib.rs | 26 +++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index f7a10a5cf59..2b2c8ff4a16 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -98,10 +98,12 @@ fn ledger_mainnet_u64_wasm() -> Vec { .unwrap() } +#[cfg(not(feature = "u256-tokens"))] fn ledger_mainnet_v2_u64_wasm() -> Vec { std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH").unwrap()).unwrap() } +#[cfg(not(feature = "u256-tokens"))] fn ledger_mainnet_v1_u64_wasm() -> Vec { std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH").unwrap()).unwrap() } @@ -111,10 +113,12 @@ fn ledger_mainnet_u256_wasm() -> Vec { .unwrap() } +#[cfg(feature = "u256-tokens")] fn ledger_mainnet_v2_u256_wasm() -> Vec { std::fs::read(std::env::var("CKETH_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH").unwrap()).unwrap() } +#[cfg(feature = "u256-tokens")] fn ledger_mainnet_v1_u256_wasm() -> Vec { std::fs::read(std::env::var("CKETH_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH").unwrap()).unwrap() } @@ -630,6 +634,15 @@ fn icrc1_test_metrics_while_migrating_from_v2() { ); } +#[test] +fn icrc1_test_upgrade_from_v1_not_possible() { + ic_ledger_suite_state_machine_tests::test_upgrade_from_v1_not_possible( + ledger_mainnet_v1_wasm(), + ledger_wasm(), + encode_init_args, + ); +} + mod metrics { use crate::{encode_init_args, encode_upgrade_args, ledger_wasm}; use ic_ledger_suite_state_machine_tests::metrics::LedgerSuiteType; diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index f6932170a8c..b7c030a8539 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3215,6 +3215,32 @@ pub fn test_metrics_while_migrating( ); } +pub fn test_upgrade_from_v1_not_possible( + ledger_wasm_mainnet_v1: Vec, + ledger_wasm_current: Vec, + encode_init_args: fn(InitArgs) -> T, +) where + T: CandidType, +{ + // Setup ledger with v1 state that does not use UPGRADES_MEMORY. + let (env, canister_id) = setup(ledger_wasm_mainnet_v1, encode_init_args, vec![]); + + match env.upgrade_canister( + canister_id, + ledger_wasm_current, + Encode!(&LedgerArgument::Upgrade(None)).unwrap(), + ) { + Ok(_) => { + panic!("Upgrade from V1 should fail!") + } + Err(e) => { + assert!(e + .description() + .contains("Cannot upgrade from scratch stable memory, please upgrade to memory manager first.")); + } + }; +} + pub fn default_approve_args(spender: impl Into, amount: u64) -> ApproveArgs { ApproveArgs { from_subaccount: None, From 192fe5cbb1634430f272c55990ef38faf3da1ac9 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 14:23:59 +0000 Subject: [PATCH 26/69] fix log message --- rs/ledger_suite/icrc1/ledger/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index bb99cbd9878..98f51c95285 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -239,7 +239,7 @@ fn post_upgrade(args: Option) { if upgrade_from_version < 2 { set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); - log_message("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data."); + log_message(format!("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data.").as_str()); clear_stable_balances_data(); Access::with_ledger_mut(|ledger| { ledger.copy_token_pool(); From 43e3e63729d726aca3b38c39b6cdfd7696b80376 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 3 Dec 2024 18:02:38 +0000 Subject: [PATCH 27/69] clippy --- rs/ledger_suite/icrc1/ledger/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/BUILD.bazel b/rs/ledger_suite/icrc1/ledger/BUILD.bazel index 3df7ea72c9b..afaec0a3b60 100644 --- a/rs/ledger_suite/icrc1/ledger/BUILD.bazel +++ b/rs/ledger_suite/icrc1/ledger/BUILD.bazel @@ -281,9 +281,9 @@ rust_test( "@mainnet_ckbtc_ic-icrc1-ledger-v1//file", "@mainnet_ckbtc_ic-icrc1-ledger-v2//file", "@mainnet_ckbtc_ic-icrc1-ledger//file", - "@mainnet_cketh_ic-icrc1-ledger-u256//file", "@mainnet_cketh_ic-icrc1-ledger-u256-v1//file", "@mainnet_cketh_ic-icrc1-ledger-u256-v2//file", + "@mainnet_cketh_ic-icrc1-ledger-u256//file", "@mainnet_ic-icrc1-ledger//file", ], env = { From 813da56335caf8bad9f42e6849304b4799fc2495 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 4 Dec 2024 11:31:34 +0000 Subject: [PATCH 28/69] remove account trimming init and upgrade args --- rs/ledger_suite/icrc1/index-ng/tests/tests.rs | 1 - rs/ledger_suite/icrc1/ledger/ledger.did | 3 --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 22 ++----------------- rs/ledger_suite/icrc1/ledger/src/tests.rs | 2 -- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 14 ------------ 5 files changed, 2 insertions(+), 40 deletions(-) diff --git a/rs/ledger_suite/icrc1/index-ng/tests/tests.rs b/rs/ledger_suite/icrc1/index-ng/tests/tests.rs index 80369d5d978..f7840498234 100644 --- a/rs/ledger_suite/icrc1/index-ng/tests/tests.rs +++ b/rs/ledger_suite/icrc1/index-ng/tests/tests.rs @@ -55,7 +55,6 @@ fn upgrade_ledger( change_fee_collector, max_memo_length: None, feature_flags: None, - accounts_overflow_trim_quantity: None, change_archive_options: None, })); env.upgrade_canister(ledger_id, ledger_wasm(), Encode!(&args).unwrap()) diff --git a/rs/ledger_suite/icrc1/ledger/ledger.did b/rs/ledger_suite/icrc1/ledger/ledger.did index dece15d9bba..b3a6c474c35 100644 --- a/rs/ledger_suite/icrc1/ledger/ledger.did +++ b/rs/ledger_suite/icrc1/ledger/ledger.did @@ -107,8 +107,6 @@ type InitArgs = record { metadata : vec record { text; MetadataValue }; initial_balances : vec record { Account; nat }; feature_flags : opt FeatureFlags; - maximum_number_of_accounts : opt nat64; - accounts_overflow_trim_quantity : opt nat64; archive_options : record { num_blocks_to_archive : nat64; max_transactions_per_response : opt nat64; @@ -144,7 +142,6 @@ type UpgradeArgs = record { change_fee_collector : opt ChangeFeeCollector; max_memo_length : opt nat16; feature_flags : opt FeatureFlags; - accounts_overflow_trim_quantity: opt nat64; change_archive_options : opt ChangeArchiveOptions; }; diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index a0837682dd9..e31c7492c88 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -183,8 +183,6 @@ impl InitArgsBuilder { }, max_memo_length: None, feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, }) } @@ -267,8 +265,6 @@ pub struct InitArgs { pub archive_options: ArchiveOptions, pub max_memo_length: Option, pub feature_flags: Option, - pub maximum_number_of_accounts: Option, - pub accounts_overflow_trim_quantity: Option, } #[derive(Clone, Eq, PartialEq, Debug, CandidType, Deserialize)] @@ -344,8 +340,6 @@ pub struct UpgradeArgs { #[serde(default, skip_serializing_if = "Option::is_none")] pub feature_flags: Option, #[serde(default, skip_serializing_if = "Option::is_none")] - pub accounts_overflow_trim_quantity: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] pub change_archive_options: Option, } @@ -644,8 +638,6 @@ impl Ledger { fee_collector_account, max_memo_length, feature_flags, - maximum_number_of_accounts, - accounts_overflow_trim_quantity, }: InitArgs, now: TimeStamp, ) -> Self { @@ -680,14 +672,8 @@ impl Ledger { .collect(), max_memo_length: max_memo_length.unwrap_or(DEFAULT_MAX_MEMO_LENGTH), feature_flags: feature_flags.unwrap_or_default(), - maximum_number_of_accounts: maximum_number_of_accounts - .unwrap_or_else(|| MAX_ACCOUNTS.try_into().unwrap()) - .try_into() - .unwrap(), - accounts_overflow_trim_quantity: accounts_overflow_trim_quantity - .unwrap_or_else(|| ACCOUNTS_OVERFLOW_TRIM_QUANTITY.try_into().unwrap()) - .try_into() - .unwrap(), + maximum_number_of_accounts: MAX_ACCOUNTS.try_into().unwrap(), + accounts_overflow_trim_quantity: ACCOUNTS_OVERFLOW_TRIM_QUANTITY.try_into().unwrap(), ledger_version: LEDGER_VERSION, }; @@ -935,10 +921,6 @@ impl Ledger { } self.feature_flags = feature_flags; } - if let Some(accounts_overflow_trim_quantity) = args.accounts_overflow_trim_quantity { - self.accounts_overflow_trim_quantity = - accounts_overflow_trim_quantity.try_into().unwrap(); - } if let Some(change_archive_options) = args.change_archive_options { let mut maybe_archive = self.blockchain.archive.write().expect( "BUG: should be unreachable since upgrade has exclusive write access to the ledger", diff --git a/rs/ledger_suite/icrc1/ledger/src/tests.rs b/rs/ledger_suite/icrc1/ledger/src/tests.rs index ca5634b81d4..5b177a13dbc 100644 --- a/rs/ledger_suite/icrc1/ledger/src/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/src/tests.rs @@ -85,8 +85,6 @@ fn default_init_args() -> InitArgs { }, max_memo_length: None, feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, } } diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index 2b2c8ff4a16..cf6296dab2a 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -189,8 +189,6 @@ fn encode_init_args(args: ic_ledger_suite_state_machine_tests::InitArgs) -> Ledg }, max_memo_length: None, feature_flags: args.feature_flags, - maximum_number_of_accounts: args.maximum_number_of_accounts, - accounts_overflow_trim_quantity: args.accounts_overflow_trim_quantity, }) } @@ -754,8 +752,6 @@ fn test_icrc2_feature_flag_doesnt_disable_icrc2_endpoints() { }, max_memo_length: None, feature_flags: Some(FeatureFlags { icrc2: false }), - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, })) .unwrap(); let ledger_id = env @@ -930,8 +926,6 @@ fn test_icrc3_get_archives() { }, max_memo_length: None, feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, }); let args = Encode!(&args).unwrap(); let ledger_id = env @@ -1007,8 +1001,6 @@ fn test_icrc3_get_blocks() { }, max_memo_length: None, feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, }); let args = Encode!(&args).unwrap(); let ledger_id = env @@ -1283,8 +1275,6 @@ fn test_icrc3_get_blocks_number_of_blocks_limit() { }, max_memo_length: None, feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, }); let args = Encode!(&args).unwrap(); @@ -1719,8 +1709,6 @@ mod verify_written_blocks { }, max_memo_length: None, feature_flags: Some(FeatureFlags { icrc2: true }), - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, }); let args = Encode!(&ledger_arg_init).unwrap(); @@ -1937,8 +1925,6 @@ mod incompatible_token_type_upgrade { }, max_memo_length: None, feature_flags: Some(FeatureFlags { icrc2: false }), - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, })) .unwrap() } From ab6fbc1bfcd7f770146fa69debd435ecba3dbaaa Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 4 Dec 2024 11:41:11 +0000 Subject: [PATCH 29/69] clippy --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index e31c7492c88..8daaa480f39 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -672,8 +672,8 @@ impl Ledger { .collect(), max_memo_length: max_memo_length.unwrap_or(DEFAULT_MAX_MEMO_LENGTH), feature_flags: feature_flags.unwrap_or_default(), - maximum_number_of_accounts: MAX_ACCOUNTS.try_into().unwrap(), - accounts_overflow_trim_quantity: ACCOUNTS_OVERFLOW_TRIM_QUANTITY.try_into().unwrap(), + maximum_number_of_accounts: MAX_ACCOUNTS, + accounts_overflow_trim_quantity: ACCOUNTS_OVERFLOW_TRIM_QUANTITY, ledger_version: LEDGER_VERSION, }; From be7510f9afe24be7342ecacbf209b5bf5de84630 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 4 Dec 2024 11:55:28 +0000 Subject: [PATCH 30/69] clippy --- rs/ethereum/ledger-suite-orchestrator/src/scheduler/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rs/ethereum/ledger-suite-orchestrator/src/scheduler/mod.rs b/rs/ethereum/ledger-suite-orchestrator/src/scheduler/mod.rs index 29f4dca688e..2d0712d5d4f 100644 --- a/rs/ethereum/ledger-suite-orchestrator/src/scheduler/mod.rs +++ b/rs/ethereum/ledger-suite-orchestrator/src/scheduler/mod.rs @@ -932,8 +932,6 @@ fn icrc1_ledger_init_arg( ), max_memo_length: Some(MAX_MEMO_LENGTH), feature_flags: Some(ICRC2_FEATURE), - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, } } From cf1d5027e8700df8e17cfbf7df8b28978e3988b2 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 12:51:22 +0000 Subject: [PATCH 31/69] build fix --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index d5ad8a8675b..8437d85b6fa 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -499,7 +499,6 @@ fn icrc1_test_upgrade_serialization_from_v2() { upgrade_args, minter, true, - true, ); } @@ -548,6 +547,7 @@ fn icrc1_test_stable_migration_endpoints_disabled_from_v2() { ledger_mainnet_v2_wasm(), ledger_wasm_lowupgradeinstructionlimits(), encode_init_args, + vec![], ); } From 33a0fd640c59365a2377b012698f2a78c9e088ec Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 12:52:51 +0000 Subject: [PATCH 32/69] fix comments --- rs/ledger_suite/common/ledger_canister_core/src/ledger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index 39f949786ad..f797625b196 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -208,7 +208,7 @@ pub enum TransferError { const APPROVE_PRUNE_LIMIT: usize = 100; /// Adds a new block with the specified transaction to the ledger. -/// Prune balances and allowances if necessary. +/// Trim balances if necessary. pub fn apply_transaction( ledger: &mut L, transaction: L::Transaction, @@ -225,7 +225,7 @@ where } /// Adds a new block with the specified transaction to the ledger. -/// Do not perform any balance or allowance prunning. +/// Do not perform any balance trimming. pub fn apply_transaction_no_prunning( ledger: &mut L, transaction: L::Transaction, From c730fc2691ac56d2fc351074e3dfd0d193a3ad3b Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 12:56:52 +0000 Subject: [PATCH 33/69] rename function --- rs/ledger_suite/common/ledger_canister_core/src/ledger.rs | 4 ++-- rs/ledger_suite/icrc1/ledger/src/lib.rs | 4 ++-- rs/ledger_suite/icrc1/ledger/src/main.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index f797625b196..30e9d972a98 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -219,14 +219,14 @@ where L: LedgerData, L::BalancesStore: InspectableBalancesStore, { - let result = apply_transaction_no_prunning(ledger, transaction, now, effective_fee); + let result = apply_transaction_no_trimming(ledger, transaction, now, effective_fee); trim_balances(ledger, now); result } /// Adds a new block with the specified transaction to the ledger. /// Do not perform any balance trimming. -pub fn apply_transaction_no_prunning( +pub fn apply_transaction_no_trimming( ledger: &mut L, transaction: L::Transaction, now: TimeStamp, diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index f497f3f31a2..267e9e19ae5 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -23,7 +23,7 @@ use ic_ledger_canister_core::{ archive::ArchiveCanisterWasm, blockchain::Blockchain, ledger::{ - apply_transaction_no_prunning, block_locations, LedgerContext, LedgerData, TransactionInfo, + apply_transaction_no_trimming, block_locations, LedgerContext, LedgerData, TransactionInfo, }, range_utils, }; @@ -685,7 +685,7 @@ impl Ledger { ) }); let mint = Transaction::mint(account, amount, Some(now), None); - apply_transaction_no_prunning(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else( + apply_transaction_no_trimming(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else( |err| { panic!( "failed to mint {} tokens to {}: {:?}", diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 98f51c95285..f7aacbfa47d 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -21,7 +21,7 @@ use ic_icrc1_ledger::{ }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; use ic_ledger_canister_core::ledger::{ - apply_transaction_no_prunning, archive_blocks, LedgerAccess, LedgerContext, LedgerData, + apply_transaction_no_trimming, archive_blocks, LedgerAccess, LedgerContext, LedgerData, TransferError as CoreTransferError, }; use ic_ledger_canister_core::runtime::heap_memory_size_bytes; @@ -669,7 +669,7 @@ fn execute_transfer_not_async( ) }; - let (block_idx, _) = apply_transaction_no_prunning(ledger, tx, now, effective_fee)?; + let (block_idx, _) = apply_transaction_no_trimming(ledger, tx, now, effective_fee)?; Ok(block_idx) }) } @@ -868,7 +868,7 @@ async fn icrc2_approve(arg: ApproveArgs) -> Result { memo: arg.memo, }; - let (block_idx, _) = apply_transaction_no_prunning(ledger, tx, now, expected_fee_tokens) + let (block_idx, _) = apply_transaction_no_trimming(ledger, tx, now, expected_fee_tokens) .map_err(convert_transfer_error) .map_err(|err| { let err: ApproveError = match err.try_into() { From d3b690d2005967f11100b5aa78388f94b6cd2ee0 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 13:51:28 +0000 Subject: [PATCH 34/69] implement v4 for icp --- Cargo.lock | 48 +++++----- .../common/ledger_canister_core/src/ledger.rs | 96 +------------------ .../common/ledger_core/src/balances.rs | 21 ---- .../common/ledger_core/src/tokens.rs | 19 ++++ rs/ledger_suite/icp/ledger/src/lib.rs | 84 +++++++++++++++- rs/ledger_suite/icp/ledger/src/main.rs | 26 +++-- rs/ledger_suite/icp/ledger/tests/tests.rs | 5 - rs/ledger_suite/icrc1/ledger/src/lib.rs | 18 ++-- rs/ledger_suite/icrc1/ledger/src/main.rs | 6 +- rs/ledger_suite/tests/sm-tests/src/lib.rs | 45 --------- 10 files changed, 154 insertions(+), 214 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 604edc80b6f..ab968a1361a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "abnf" @@ -4423,7 +4423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-pki-types", ] @@ -5047,7 +5047,7 @@ dependencies = [ "clap 4.5.20", "hyper 1.5.1", "hyper-util", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-pemfile 2.2.0", "serde_json", "tokio", @@ -5176,7 +5176,7 @@ dependencies = [ "hyper 1.5.1", "hyper-util", "log", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -5700,7 +5700,7 @@ dependencies = [ "rand 0.8.5", "rcgen", "reqwest 0.12.9", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-acme", "rustls-pemfile 2.2.0", "rustls-platform-verifier", @@ -5793,7 +5793,7 @@ dependencies = [ "rcgen", "regex", "reqwest 0.12.9", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-pemfile 2.2.0", "serde", "serde_bytes", @@ -6134,7 +6134,7 @@ dependencies = [ "prost 0.13.3", "rand 0.8.5", "rand_chacha 0.3.1", - "rustls 0.23.19", + "rustls 0.23.18", "serde", "serde_cbor", "tokio", @@ -7024,7 +7024,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rsa", - "rustls 0.23.19", + "rustls 0.23.18", "serde", "sha2 0.10.8", "simple_asn1", @@ -7784,7 +7784,7 @@ dependencies = [ "ic-types-test-utils", "rand 0.8.5", "rand_chacha 0.3.1", - "rustls 0.23.19", + "rustls 0.23.18", "tempfile", "tokio", ] @@ -7984,7 +7984,7 @@ dependencies = [ "ic-types", "pkcs8", "rand 0.8.5", - "rustls 0.23.19", + "rustls 0.23.18", "signature", "time", "tokio", @@ -8020,7 +8020,7 @@ dependencies = [ "ic-types", "json5", "maplit", - "rustls 0.23.19", + "rustls 0.23.18", "serde", "thiserror 2.0.3", "x509-parser", @@ -8033,7 +8033,7 @@ dependencies = [ "ic-base-types", "ic-crypto-tls-interfaces", "mockall", - "rustls 0.23.19", + "rustls 0.23.18", ] [[package]] @@ -8550,7 +8550,7 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.9", "rstest", - "rustls 0.23.19", + "rustls 0.23.18", "serde", "serde_bytes", "serde_cbor", @@ -8670,7 +8670,7 @@ dependencies = [ "prometheus", "rand 0.8.5", "rstest", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-pemfile 2.2.0", "serde", "serde_json", @@ -10824,7 +10824,7 @@ dependencies = [ "quinn", "quinn-udp", "rcgen", - "rustls 0.23.19", + "rustls 0.23.18", "serde", "slog", "tempfile", @@ -10988,7 +10988,7 @@ dependencies = [ "prost 0.13.3", "quinn", "rstest", - "rustls 0.23.19", + "rustls 0.23.18", "slog", "socket2 0.5.7", "static_assertions", @@ -14831,7 +14831,7 @@ dependencies = [ "k8s-openapi", "kube-core", "pem 3.0.4", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-pemfile 2.2.0", "secrecy", "serde", @@ -17952,7 +17952,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.19", + "rustls 0.23.18", "socket2 0.5.7", "thiserror 1.0.68", "tokio", @@ -17969,7 +17969,7 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.19", + "rustls 0.23.18", "slab", "thiserror 1.0.68", "tinyvec", @@ -18595,7 +18595,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -19010,9 +19010,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ "brotli 7.0.0", "brotli-decompressor", @@ -19112,7 +19112,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.19", + "rustls 0.23.18", "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", @@ -21192,7 +21192,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.19", + "rustls 0.23.18", "rustls-pki-types", "tokio", ] diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index 30e9d972a98..8523d20a694 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -4,22 +4,18 @@ use ic_canister_log::{log, Sink}; use ic_ledger_core::approvals::{ AllowanceTable, AllowancesData, ApproveError, InsufficientAllowance, }; -use ic_ledger_core::tokens::Zero; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, VecDeque}; use std::ops::Range; use std::time::Duration; use crate::archive::{ArchivingGuardError, FailedToArchiveBlocks, LedgerArchivingGuard}; -use ic_ledger_core::balances::{BalanceError, Balances, BalancesStore, InspectableBalancesStore}; +use ic_ledger_core::balances::{BalanceError, Balances, BalancesStore}; use ic_ledger_core::block::{BlockIndex, BlockType, EncodedBlock, FeeCollector}; use ic_ledger_core::timestamp::TimeStamp; use ic_ledger_core::tokens::TokensType; use ic_ledger_hash_of::HashOf; -/// The memo to use for balances burned and approvals reset to 0 during trimming -const TRIMMED_MEMO: u64 = u64::MAX; - #[derive(Debug, Deserialize, Serialize)] pub struct TransactionInfo { pub block_timestamp: TimeStamp, @@ -207,26 +203,9 @@ pub enum TransferError { const APPROVE_PRUNE_LIMIT: usize = 100; -/// Adds a new block with the specified transaction to the ledger. -/// Trim balances if necessary. -pub fn apply_transaction( - ledger: &mut L, - transaction: L::Transaction, - now: TimeStamp, - effective_fee: L::Tokens, -) -> Result<(BlockIndex, HashOf), TransferError> -where - L: LedgerData, - L::BalancesStore: InspectableBalancesStore, -{ - let result = apply_transaction_no_trimming(ledger, transaction, now, effective_fee); - trim_balances(ledger, now); - result -} - /// Adds a new block with the specified transaction to the ledger. /// Do not perform any balance trimming. -pub fn apply_transaction_no_trimming( +pub fn apply_transaction( ledger: &mut L, transaction: L::Transaction, now: TimeStamp, @@ -322,44 +301,6 @@ where Ok((height, ledger.blockchain().last_hash.unwrap())) } -/// Trim balances. Can be used e.g. if the ledger is low on heap memory. -fn trim_balances(ledger: &mut L, now: TimeStamp) -where - L: LedgerData, - L::BalancesStore: InspectableBalancesStore, -{ - let effective_max_number_of_accounts = - ledger.max_number_of_accounts() + ledger.accounts_overflow_trim_quantity() - 1; - - let to_trim = if ledger.balances().store.len() > effective_max_number_of_accounts { - select_accounts_to_trim(ledger) - } else { - vec![] - }; - - for (balance, account) in to_trim { - let burn_tx = L::Transaction::burn(account, None, balance, Some(now), Some(TRIMMED_MEMO)); - - burn_tx - .apply(ledger, now, L::Tokens::zero()) - .expect("failed to burn funds that must have existed"); - - let parent_hash = ledger.blockchain().last_hash; - let fee_collector = ledger.fee_collector().cloned(); - - ledger - .blockchain_mut() - .add_block(L::Block::from_transaction( - parent_hash, - burn_tx, - now, - L::Tokens::zero(), - fee_collector, - )) - .unwrap(); - } -} - /// Finds the archive canister that contains the block with the specified height. pub fn find_block_in_archive(ledger: &L, block_height: u64) -> Option { let index = ledger @@ -453,39 +394,6 @@ pub fn purge_old_transactions(ledger: &mut L, now: TimeStamp) -> num_tx_purged } -// Find the specified number of accounts with lowest balances so that their -// balances can be reclaimed. -fn select_accounts_to_trim(ledger: &L) -> Vec<(L::Tokens, L::AccountId)> -where - L: LedgerData, - L::BalancesStore: InspectableBalancesStore, - L::Tokens: TokensType, -{ - let mut to_trim: std::collections::BinaryHeap<(L::Tokens, L::AccountId)> = - std::collections::BinaryHeap::new(); - - let num_accounts = ledger.accounts_overflow_trim_quantity(); - let mut iter = ledger.balances().store.iter(); - - // Accumulate up to `trim_quantity` accounts - for (account, balance) in iter.by_ref().take(num_accounts) { - to_trim.push((balance.clone(), account.clone())); - } - - for (account, balance) in iter { - // If any account's balance is lower than the maximum in our set, - // include that account, and remove the current maximum - if let Some((greatest_balance, _)) = to_trim.peek() { - if balance < greatest_balance { - to_trim.push((balance.clone(), account.clone())); - to_trim.pop(); - } - } - } - - to_trim.into_vec() -} - /// Asynchronously archives a suffix of the locally available blockchain. /// /// NOTE: only one archiving task can run at each point in time. diff --git a/rs/ledger_suite/common/ledger_core/src/balances.rs b/rs/ledger_suite/common/ledger_core/src/balances.rs index 68d9791b879..cd229dfcabe 100644 --- a/rs/ledger_suite/common/ledger_core/src/balances.rs +++ b/rs/ledger_suite/common/ledger_core/src/balances.rs @@ -19,13 +19,6 @@ pub trait BalancesStore { F: FnMut(Option<&Self::Tokens>) -> Result; } -#[allow(clippy::len_without_is_empty)] -pub trait InspectableBalancesStore: BalancesStore { - fn iter(&self) -> Box + '_>; - - fn len(&self) -> usize; -} - impl BalancesStore for BTreeMap where AccountId: Eq + Clone + std::cmp::Ord, @@ -63,20 +56,6 @@ where } } -impl InspectableBalancesStore for BTreeMap -where - AccountId: Eq + Clone + std::cmp::Ord, - Tokens: TokensType, -{ - fn len(&self) -> usize { - self.len() - } - - fn iter(&self) -> Box + '_> { - Box::new(self.iter()) - } -} - /// An error returned by `Balances` if the debit operation fails. #[derive(Debug)] pub enum BalanceError { diff --git a/rs/ledger_suite/common/ledger_core/src/tokens.rs b/rs/ledger_suite/common/ledger_core/src/tokens.rs index 3707aa1dae4..f4b03b56324 100644 --- a/rs/ledger_suite/common/ledger_core/src/tokens.rs +++ b/rs/ledger_suite/common/ledger_core/src/tokens.rs @@ -1,7 +1,9 @@ use candid::{CandidType, Nat}; +use ic_stable_structures::{storable::Bound, Storable}; use minicbor::{Decode, Encode}; use num_traits::{Bounded, ToPrimitive}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::borrow::Cow; use std::fmt; use std::fmt::Debug; @@ -302,3 +304,20 @@ impl From for Nat { Nat::from(value.e8s) } } + +impl Storable for Tokens { + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Owned(self.e8s.to_le_bytes().to_vec()) + } + + fn from_bytes(bytes: Cow<[u8]>) -> Self { + Self { + e8s: u64::from_le_bytes(bytes.into_owned().as_slice().try_into().unwrap()), + } + } + + const BOUND: Bound = Bound::Bounded { + max_size: 8, + is_fixed_size: true, + }; +} diff --git a/rs/ledger_suite/icp/ledger/src/lib.rs b/rs/ledger_suite/icp/ledger/src/lib.rs index d401537dd74..60cfdfd2ccd 100644 --- a/rs/ledger_suite/icp/ledger/src/lib.rs +++ b/rs/ledger_suite/icp/ledger/src/lib.rs @@ -5,6 +5,7 @@ use ic_ledger_canister_core::blockchain::Blockchain; use ic_ledger_canister_core::ledger::{ self as core_ledger, LedgerContext, LedgerData, TransactionInfo, }; +use ic_ledger_core::balances::BalancesStore; use ic_ledger_core::{ approvals::{Allowance, AllowanceTable, AllowancesData}, balances::Balances, @@ -75,6 +76,7 @@ fn default_ledger_version() -> u64 { const UPGRADES_MEMORY_ID: MemoryId = MemoryId::new(0); const ALLOWANCES_MEMORY_ID: MemoryId = MemoryId::new(1); const ALLOWANCES_EXPIRATIONS_MEMORY_ID: MemoryId = MemoryId::new(2); +const BALANCES_MEMORY_ID: MemoryId = MemoryId::new(3); #[derive(Clone, Debug, Encode, Decode)] struct StorableAllowance { @@ -142,12 +144,17 @@ thread_local! { #[allow(clippy::type_complexity)] pub static ALLOWANCES_EXPIRATIONS_MEMORY: RefCell>> = MEMORY_MANAGER.with(|memory_manager| RefCell::new(StableBTreeMap::init(memory_manager.borrow().get(ALLOWANCES_EXPIRATIONS_MEMORY_ID)))); + + // account -> tokens - map storing ledger balances. + pub static BALANCES_MEMORY: RefCell>> = + MEMORY_MANAGER.with(|memory_manager| RefCell::new(StableBTreeMap::init(memory_manager.borrow().get(BALANCES_MEMORY_ID)))); } #[derive(Copy, Clone, Serialize, Deserialize, Debug)] pub enum LedgerField { Allowances, AllowancesExpirations, + Balances, } #[derive(Copy, Clone, Serialize, Deserialize, Debug)] @@ -168,16 +175,21 @@ impl Default for LedgerState { /// We have the following ledger versions: /// * 0 - the whole ledger state is stored on the heap. /// * 1 - the allowances are stored in stable structures. +/// * 2 - the balances are stored in stable structures. #[cfg(not(feature = "next-ledger-version"))] -pub const LEDGER_VERSION: u64 = 1; +pub const LEDGER_VERSION: u64 = 2; #[cfg(feature = "next-ledger-version")] -pub const LEDGER_VERSION: u64 = 2; +pub const LEDGER_VERSION: u64 = 3; + +type StableLedgerBalances = Balances; #[derive(Debug, Deserialize, Serialize)] pub struct Ledger { balances: LedgerBalances, #[serde(default)] + stable_balances: StableLedgerBalances, + #[serde(default)] approvals: LedgerAllowances, #[serde(default)] stable_approvals: AllowanceTable, @@ -229,17 +241,17 @@ pub struct Ledger { impl LedgerContext for Ledger { type AccountId = AccountIdentifier; type AllowancesData = StableAllowancesData; - type BalancesStore = BTreeMap; + type BalancesStore = StableBalances; type Tokens = Tokens; fn balances(&self) -> &Balances { panic_if_not_ready(); - &self.balances + &self.stable_balances } fn balances_mut(&mut self) -> &mut Balances { panic_if_not_ready(); - &mut self.balances + &mut self.stable_balances } fn approvals(&self) -> &AllowanceTable { @@ -330,6 +342,7 @@ impl Default for Ledger { fn default() -> Self { Self { approvals: Default::default(), + stable_balances: StableLedgerBalances::default(), stable_approvals: Default::default(), balances: LedgerBalances::default(), blockchain: Blockchain::default(), @@ -593,9 +606,23 @@ impl Ledger { } } + pub fn migrate_one_balance(&mut self) -> bool { + match self.balances.store.pop_first() { + Some((account, tokens)) => { + self.stable_balances.credit(&account, tokens); + true + } + None => false, + } + } + pub fn clear_arrivals(&mut self) { self.approvals.allowances_data.clear_arrivals(); } + + pub fn copy_token_pool(&mut self) { + self.stable_balances.token_pool = self.balances.token_pool; + } } pub fn add_payment( @@ -650,6 +677,16 @@ pub fn clear_stable_allowance_data() { }); } +pub fn clear_stable_balances_data() { + BALANCES_MEMORY.with_borrow_mut(|balances| { + balances.clear_new(); + }); +} + +pub fn balances_len() -> u64 { + BALANCES_MEMORY.with_borrow(|balances| balances.len()) +} + #[derive(Serialize, Deserialize, Debug, Default)] pub struct StableAllowancesData {} @@ -733,3 +770,40 @@ impl AllowancesData for StableAllowancesData { panic!("The method `clear_arrivals` should not be called for StableAllowancesData") } } + +#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] +pub struct StableBalances {} + +impl BalancesStore for StableBalances { + type AccountId = AccountIdentifier; + type Tokens = Tokens; + + fn get_balance(&self, k: &AccountIdentifier) -> Option { + BALANCES_MEMORY.with_borrow(|balances| balances.get(k)) + } + + fn update(&mut self, k: AccountIdentifier, mut f: F) -> Result + where + F: FnMut(Option<&Tokens>) -> Result, + { + let entry = BALANCES_MEMORY.with_borrow(|balances| balances.get(&k)); + match entry { + Some(v) => { + let new_v = f(Some(&v))?; + if new_v != Tokens::ZERO { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.insert(k, new_v)); + } else { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.remove(&k)); + } + Ok(new_v) + } + None => { + let new_v = f(None)?; + if new_v != Tokens::ZERO { + BALANCES_MEMORY.with_borrow_mut(|balances| balances.insert(k, new_v)); + } + Ok(new_v) + } + } + } +} diff --git a/rs/ledger_suite/icp/ledger/src/main.rs b/rs/ledger_suite/icp/ledger/src/main.rs index 1b16dba8bf6..7107be238ab 100644 --- a/rs/ledger_suite/icp/ledger/src/main.rs +++ b/rs/ledger_suite/icp/ledger/src/main.rs @@ -57,9 +57,9 @@ use icrc_ledger_types::{ icrc21::{errors::Icrc21Error, requests::ConsentMessageRequest, responses::ConsentInfo}, }; use ledger_canister::{ - clear_stable_allowance_data, is_ready, ledger_state, panic_if_not_ready, set_ledger_state, - Ledger, LedgerField, LedgerState, LEDGER, LEDGER_VERSION, MAX_MESSAGE_SIZE_BYTES, - UPGRADES_MEMORY, + balances_len, clear_stable_allowance_data, clear_stable_balances_data, is_ready, ledger_state, + panic_if_not_ready, set_ledger_state, Ledger, LedgerField, LedgerState, LEDGER, LEDGER_VERSION, + MAX_MESSAGE_SIZE_BYTES, UPGRADES_MEMORY, }; use num_traits::cast::ToPrimitive; #[allow(unused_imports)] @@ -839,6 +839,12 @@ fn post_upgrade(args: Option) { PRE_UPGRADE_INSTRUCTIONS_CONSUMED .with(|n| *n.borrow_mut() = pre_upgrade_instructions_consumed); + if upgrade_from_version < 2 { + set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); + print(format!("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data.").as_str()); + clear_stable_balances_data(); + ledger.copy_token_pool(); + } if upgrade_from_version == 0 { set_ledger_state(LedgerState::Migrating(LedgerField::Allowances)); print("Upgrading from version 0 which does not use stable structures, clearing stable allowance data."); @@ -864,6 +870,7 @@ fn migrate_next_part(instruction_limit: u64) { STABLE_UPGRADE_MIGRATION_STEPS.with(|n| *n.borrow_mut() += 1); let mut migrated_allowances = 0; let mut migrated_expirations = 0; + let mut migrated_balances = 0; print("Migrating part of the ledger state."); @@ -884,6 +891,13 @@ fn migrate_next_part(instruction_limit: u64) { LedgerField::AllowancesExpirations => { if ledger.migrate_one_expiration() { migrated_expirations += 1; + } else { + set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); + } + } + LedgerField::Balances => { + if ledger.migrate_one_balance() { + migrated_balances += 1; } else { set_ledger_state(LedgerState::Ready); } @@ -891,8 +905,8 @@ fn migrate_next_part(instruction_limit: u64) { } } let instructions_migration = instruction_counter() - instructions_migration_start; - let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , - instruction_counter()); + let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations} balances: {migrated_balances}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , + instruction_counter()); if !is_ready() { print(format!( "Migration partially done. Scheduling the next part. {msg}" @@ -1495,7 +1509,7 @@ fn encode_metrics(w: &mut ic_metrics_encoder::MetricsEncoder>) -> std::i )?; w.encode_gauge( "ledger_balance_store_entries", - ledger.balances().store.len() as f64, + balances_len() as f64, "Total number of accounts in the balance store.", )?; } diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index fbbd48ce829..40d4cddef55 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1504,11 +1504,6 @@ fn test_transfer_from_burn() { ic_ledger_suite_state_machine_tests::test_transfer_from_burn(ledger_wasm(), encode_init_args); } -#[test] -fn test_balances_overflow() { - ic_ledger_suite_state_machine_tests::test_balances_overflow(ledger_wasm(), encode_init_args); -} - #[test] fn account_identifier_test() { let env = StateMachine::new(); diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 267e9e19ae5..2bb483f447e 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -22,9 +22,7 @@ use ic_ledger_canister_core::runtime::Runtime; use ic_ledger_canister_core::{ archive::ArchiveCanisterWasm, blockchain::Blockchain, - ledger::{ - apply_transaction_no_trimming, block_locations, LedgerContext, LedgerData, TransactionInfo, - }, + ledger::{apply_transaction, block_locations, LedgerContext, LedgerData, TransactionInfo}, range_utils, }; use ic_ledger_core::balances::BalancesStore; @@ -685,14 +683,12 @@ impl Ledger { ) }); let mint = Transaction::mint(account, amount, Some(now), None); - apply_transaction_no_trimming(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else( - |err| { - panic!( - "failed to mint {} tokens to {}: {:?}", - balance, account, err - ) - }, - ); + apply_transaction(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else(|err| { + panic!( + "failed to mint {} tokens to {}: {:?}", + balance, account, err + ) + }); } ledger diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index f7aacbfa47d..61247b30250 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -21,7 +21,7 @@ use ic_icrc1_ledger::{ }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; use ic_ledger_canister_core::ledger::{ - apply_transaction_no_trimming, archive_blocks, LedgerAccess, LedgerContext, LedgerData, + apply_transaction, archive_blocks, LedgerAccess, LedgerContext, LedgerData, TransferError as CoreTransferError, }; use ic_ledger_canister_core::runtime::heap_memory_size_bytes; @@ -669,7 +669,7 @@ fn execute_transfer_not_async( ) }; - let (block_idx, _) = apply_transaction_no_trimming(ledger, tx, now, effective_fee)?; + let (block_idx, _) = apply_transaction(ledger, tx, now, effective_fee)?; Ok(block_idx) }) } @@ -868,7 +868,7 @@ async fn icrc2_approve(arg: ApproveArgs) -> Result { memo: arg.memo, }; - let (block_idx, _) = apply_transaction_no_trimming(ledger, tx, now, expected_fee_tokens) + let (block_idx, _) = apply_transaction(ledger, tx, now, expected_fee_tokens) .map_err(convert_transfer_error) .map_err(|err| { let err: ApproveError = match err.try_into() { diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index b807f3d7089..7cd05e194fc 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3966,51 +3966,6 @@ where assert_eq!(total_supply(&env, canister_id), 60_000); } -pub fn test_balances_overflow(ledger_wasm: Vec, encode_init_args: fn(InitArgs) -> T) -where - T: CandidType, -{ - let env = StateMachine::new(); - - let args = encode_init_args(InitArgs { - maximum_number_of_accounts: Some(8), - accounts_overflow_trim_quantity: Some(2), - ..init_args(vec![]) - }); - let args = Encode!(&args).unwrap(); - let canister_id = env.install_canister(ledger_wasm, args, None).unwrap(); - - let minter = minting_account(&env, canister_id).unwrap(); - - let mut credited = 0; - for i in 0..11 { - transfer( - &env, - canister_id, - minter, - PrincipalId::new_user_test_id(i).0, - i, - ) - .expect("failed to mint tokens"); - credited += i; - } - assert_eq!( - balance_of(&env, canister_id, PrincipalId::new_user_test_id(1).0), - 0 - ); - assert_eq!( - balance_of(&env, canister_id, PrincipalId::new_user_test_id(2).0), - 0 - ); - for i in 3..11 { - assert_eq!( - balance_of(&env, canister_id, PrincipalId::new_user_test_id(i).0), - i - ); - } - assert_eq!(total_supply(&env, canister_id), credited - 1 - 2); -} - pub fn test_icrc1_test_suite( ledger_wasm: Vec, encode_init_args: fn(InitArgs) -> T, From e22994c086fa02ec8474413b5e41472c8f1174fa Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 13:55:00 +0000 Subject: [PATCH 35/69] fix comments --- rs/ledger_suite/common/ledger_canister_core/src/ledger.rs | 1 - rs/ledger_suite/icp/ledger/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index 8523d20a694..e20c09c7409 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -204,7 +204,6 @@ pub enum TransferError { const APPROVE_PRUNE_LIMIT: usize = 100; /// Adds a new block with the specified transaction to the ledger. -/// Do not perform any balance trimming. pub fn apply_transaction( ledger: &mut L, transaction: L::Transaction, diff --git a/rs/ledger_suite/icp/ledger/src/lib.rs b/rs/ledger_suite/icp/ledger/src/lib.rs index 60cfdfd2ccd..de47c6092dd 100644 --- a/rs/ledger_suite/icp/ledger/src/lib.rs +++ b/rs/ledger_suite/icp/ledger/src/lib.rs @@ -175,7 +175,7 @@ impl Default for LedgerState { /// We have the following ledger versions: /// * 0 - the whole ledger state is stored on the heap. /// * 1 - the allowances are stored in stable structures. -/// * 2 - the balances are stored in stable structures. +/// * 2 - the balances are stored in stable structures. #[cfg(not(feature = "next-ledger-version"))] pub const LEDGER_VERSION: u64 = 2; From b36f5b67295f23a727aed97a2d5dbae68d2fba46 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 14:32:45 +0000 Subject: [PATCH 36/69] update cketh hash --- mainnet-canisters.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainnet-canisters.json b/mainnet-canisters.json index ef14f1cc45d..bae9a3cb0c6 100644 --- a/mainnet-canisters.json +++ b/mainnet-canisters.json @@ -32,8 +32,8 @@ "sha256": "07dd7a18d047ac41c37be9ea200dc1e0cbe4606bbc737d5dbb89f6e0a6e7450d" }, "ck_eth_ledger": { - "rev": "8d726cc67a8ec83b55e5dc6305f49c1e4304d6dd", - "sha256": "918f9cc15585f1a946f377f5c5041127b5a3261c95e6a485b0c899057ca28865" + "rev": "2190613d3b5bcd9b74c382b22d151580b8ac271a", + "sha256": "9637743e1215a4db376a62ee807a0986faf20833be2b332df09b3d5dbdd7339e" }, "ck_eth_ledger_v1": { "rev": "d4ee25b0865e89d3eaac13a60f0016d5e3296b31", From c59b7fafceca885926479148c8868ad3bb1f344c Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 16:01:33 +0000 Subject: [PATCH 37/69] remove account listing from nns inspector --- Cargo.lock | 1 - rs/nns/inspector/BUILD.bazel | 1 - rs/nns/inspector/Cargo.toml | 1 - rs/nns/inspector/src/main.rs | 78 +----------------------------------- 4 files changed, 2 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab968a1361a..b548bd93378 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10593,7 +10593,6 @@ dependencies = [ "csv", "hex", "ic-base-types", - "ic-ledger-canister-core", "ic-nns-constants", "ic-nns-governance-api", "ic-nns-gtc", diff --git a/rs/nns/inspector/BUILD.bazel b/rs/nns/inspector/BUILD.bazel index 531724a2940..0ad7574ed85 100644 --- a/rs/nns/inspector/BUILD.bazel +++ b/rs/nns/inspector/BUILD.bazel @@ -4,7 +4,6 @@ package(default_visibility = ["//visibility:public"]) DEPENDENCIES = [ # Keep sorted. - "//rs/ledger_suite/common/ledger_canister_core", "//rs/ledger_suite/icp:icp_ledger", "//rs/ledger_suite/icp/ledger", "//rs/nns/constants", diff --git a/rs/nns/inspector/Cargo.toml b/rs/nns/inspector/Cargo.toml index 83ceb74fc7a..8d38ba9a6d9 100644 --- a/rs/nns/inspector/Cargo.toml +++ b/rs/nns/inspector/Cargo.toml @@ -9,7 +9,6 @@ clap = { workspace = true } csv = "1.1" hex = { workspace = true } ic-base-types = { path = "../../types/base_types" } -ic-ledger-canister-core = { path = "../../ledger_suite/common/ledger_canister_core" } ic-nns-constants = { path = "../constants" } ic-nns-governance-api = { path = "../governance/api" } ic-nns-gtc = { path = "../gtc" } diff --git a/rs/nns/inspector/src/main.rs b/rs/nns/inspector/src/main.rs index 8c77da9169a..ee12e062c8d 100644 --- a/rs/nns/inspector/src/main.rs +++ b/rs/nns/inspector/src/main.rs @@ -2,10 +2,9 @@ use clap::Parser; use ic_base_types::CanisterId; -use ic_ledger_canister_core::ledger::LedgerContext; use ic_nns_constants::{ CYCLES_MINTING_CANISTER_ID, GENESIS_TOKEN_CANISTER_ID, GOVERNANCE_CANISTER_ID, - LEDGER_CANISTER_ID, REGISTRY_CANISTER_ID, + REGISTRY_CANISTER_ID, }; use ic_nns_governance_api::pb::v1::{Governance as GovernanceProto, Neuron}; use ic_nns_gtc::pb::v1::Gtc as GtcProto; @@ -14,7 +13,7 @@ use prost::Message; use std::{ convert::TryInto, fs::File, - io::{Read, Write}, + io::Read, path::{Path, PathBuf}, string::ToString, }; @@ -71,13 +70,6 @@ fn main() { Err(e) => eprintln!("Could not extract the governance stable memory: {}", e), } - // Ledger. - // Stable memory = binary CBOR, type Ledger (rust struct). - match extract_stable_memory(&args, LEDGER_CANISTER_ID, "ledger_stable_memory.cbor") { - Ok(cbor) => decode_ledger_stable_memory(cbor, &args.output), - Err(e) => eprintln!("Could not extract the ledger stable memory: {}", e), - } - // Gtc. // Stable memory = binary proto, type Gtc. match extract_stable_memory(&args, GENESIS_TOKEN_CANISTER_ID, "gtc_stable_memory.pb") { @@ -279,69 +271,3 @@ fn decode_gtc_stable_memory(gtc_pb: PathBuf, output: &Path, rs: &Path) { } eprintln!("Wrote gtc_accounts_EXTRACT.csv"); } - -/// The type of record expected to be found in the ledger canister's stable -/// memory. -#[derive(serde::Serialize)] -struct LedgerBalanceRecord { - account_identitifier: String, - balance_e8s: u64, -} - -/// Decode stable memory for the ledger canister. -fn decode_ledger_stable_memory(cbor: PathBuf, output: &Path) { - // For the same argument as above, do NOT deserialize to a specific struct. - // This is an audit tool, we don't want any risk of dropping data. - // So go the schema-less way. - use serde_cbor::value::Value; - let value_res: serde_cbor::Result = - serde_cbor::from_reader(File::open(cbor.clone()).unwrap()); - let val = match value_res { - Err(e) => { - eprintln!( - "Could not parse the cbor for the ledger stable memory: {}", - e - ); - return; - } - Ok(v) => v, - }; - // The following is very slow and the output is very verbose. Serialization to - // json is not a viable alternative as some keys are not strings, which is - // allowed in cbor but not in json. - match write!( - File::create(output.join("ledger_stable_memory.txt")).unwrap(), - "{:#?}", - val - ) { - Ok(()) => eprintln!("Wrote ledger_stable_memory.txt"), - Err(e) => eprintln!("Could not write ledger_stable_memory.txt: {}", e), - }; - - let ledger: ledger_canister::Ledger = match serde_cbor::from_reader(File::open(cbor).unwrap()) { - Err(e) => { - eprintln!( - "Could parse the ledger stable memory as a Ledger struct: {}", - e - ); - return; - } - Ok(l) => l, - }; - let mut records: Vec = ledger - .balances() - .store - .iter() - .map(|(key, icpts)| LedgerBalanceRecord { - account_identitifier: key.to_string(), - balance_e8s: icpts.get_e8s(), - }) - .collect(); - records.sort_by_key(|record| record.account_identitifier.clone()); - let mut csv_writer = - csv::Writer::from_path(output.join("ledger_balances_EXTRACT.csv")).unwrap(); - for r in records.into_iter() { - csv_writer.serialize(r).unwrap(); - } - eprintln!("Wrote ledger_balances_EXTRACT.csv"); -} From 377eb724efabd6f922901826fbb23ffe8248c5ea Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 16:41:59 +0000 Subject: [PATCH 38/69] fix tests --- rs/ledger_suite/icp/ledger/src/tests.rs | 96 +++++-------------------- 1 file changed, 16 insertions(+), 80 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/src/tests.rs b/rs/ledger_suite/icp/ledger/src/tests.rs index c5fe4fd4a70..80d0ac79305 100644 --- a/rs/ledger_suite/icp/ledger/src/tests.rs +++ b/rs/ledger_suite/icp/ledger/src/tests.rs @@ -1,4 +1,4 @@ -use crate::{AccountIdentifier, Ledger, StorableAllowance}; +use crate::{balances_len, AccountIdentifier, Ledger, StorableAllowance}; use ic_base_types::{CanisterId, PrincipalId}; use ic_ledger_canister_core::{ archive::Archive, @@ -7,14 +7,15 @@ use ic_ledger_canister_core::{ }; use ic_ledger_core::{ approvals::Allowance, + balances::BalancesStore, block::{BlockIndex, BlockType}, timestamp::TimeStamp, - tokens::{CheckedAdd, CheckedSub, Tokens}, + tokens::Tokens, }; use ic_stable_structures::Storable; use icp_ledger::{ - apply_operation, ArchiveOptions, Block, LedgerBalances, Memo, Operation, PaymentError, - Transaction, TransferError, DEFAULT_TRANSFER_FEE, + apply_operation, ArchiveOptions, Block, Memo, Operation, PaymentError, Transaction, + TransferError, DEFAULT_TRANSFER_FEE, }; use proptest::prelude::{any, prop_assert_eq, proptest}; use proptest::strategy::Strategy; @@ -34,71 +35,6 @@ fn ts(n: u64) -> TimeStamp { TimeStamp::from_nanos_since_unix_epoch(n) } -#[test] -fn balances_overflow() { - let balances = LedgerBalances::new(); - let mut state = Ledger { - balances, - maximum_number_of_accounts: 8, - accounts_overflow_trim_quantity: 2, - minting_account_id: Some(PrincipalId::new_user_test_id(137).into()), - ..Default::default() - }; - assert_eq!(state.balances.token_pool, Tokens::MAX); - println!( - "minting canister initial balance: {}", - state.balances.token_pool - ); - let mut credited = Tokens::ZERO; - - // 11 accounts. The one with 0 will not be added - // The rest will be added and trigger a trim of 2 once - // the total number reaches 8 + 2 - // the number of active accounts won't go below 8 after trimming - for i in 0..11 { - let amount = Tokens::new(i, 0).unwrap(); - state - .add_payment( - Memo::default(), - Operation::Mint { - to: PrincipalId::new_user_test_id(i).into(), - amount, - }, - None, - ) - .unwrap(); - credited = credited.checked_add(&amount).unwrap(); - } - println!("amount credited to accounts: {}", credited); - - println!("balances: {:?}", state.balances); - - // The two accounts with lowest balances, 0 and 1 respectively, have been - // removed - assert_eq!(state.balances.store.len(), 8); - assert_eq!( - state - .balances - .account_balance(&PrincipalId::new_user_test_id(0).into()), - Tokens::ZERO - ); - assert_eq!( - state - .balances - .account_balance(&PrincipalId::new_user_test_id(1).into()), - Tokens::ZERO - ); - // We have credited 55 Tokens to various accounts but the three accounts - // with lowest balances, 0, 1 and 2, should have been removed and their - // balance returned to the minting canister - let expected_minting_canister_balance = Tokens::MAX - .checked_sub(&credited) - .unwrap() - .checked_add(&Tokens::new(1 + 2, 0).unwrap()) - .unwrap(); - assert_eq!(state.balances.token_pool, expected_minting_canister_balance); -} - #[test] fn balances_remove_accounts_with_zero_balance() { let mut ctx = Ledger::default(); @@ -116,8 +52,8 @@ fn balances_remove_accounts_with_zero_balance() { .unwrap(); // verify that an account entry exists for the `canister` assert_eq!( - ctx.balances().store.get(&canister), - Some(&Tokens::from_e8s(1000)) + ctx.balances().store.get_balance(&canister), + Some(&Tokens::from_e8s(1000)).copied() ); // make 2 transfers that empty the account for _ in 0..2 { @@ -136,15 +72,15 @@ fn balances_remove_accounts_with_zero_balance() { } // target canister's balance adds up assert_eq!( - ctx.balances().store.get(&target_canister), - Some(&Tokens::from_e8s(800)) + ctx.balances().store.get_balance(&target_canister), + Some(&Tokens::from_e8s(800)).copied() ); // source canister has been removed - assert_eq!(ctx.balances().store.get(&canister), None); + assert_eq!(ctx.balances().store.get_balance(&canister), None); assert_eq!(ctx.balances().account_balance(&canister), Tokens::ZERO); // one account left in the store - assert_eq!(ctx.balances().store.len(), 1); + assert_eq!(balances_len(), 1); apply_operation( &mut ctx, @@ -159,11 +95,11 @@ fn balances_remove_accounts_with_zero_balance() { ) .unwrap(); // No new account should have been created - assert_eq!(ctx.balances().store.len(), 1); + assert_eq!(balances_len(), 1); // and the fee should have been taken from sender assert_eq!( - ctx.balances().store.get(&target_canister), - Some(&Tokens::from_e8s(700)) + ctx.balances().store.get_balance(&target_canister), + Some(&Tokens::from_e8s(700)).copied() ); apply_operation( @@ -177,7 +113,7 @@ fn balances_remove_accounts_with_zero_balance() { .unwrap(); // No new account should have been created - assert_eq!(ctx.balances().store.len(), 1); + assert_eq!(balances_len(), 1); apply_operation( &mut ctx, @@ -191,7 +127,7 @@ fn balances_remove_accounts_with_zero_balance() { .unwrap(); // And burn should have exhausted the target_canister - assert_eq!(ctx.balances().store.len(), 0); + assert_eq!(balances_len(), 0); } #[test] From 5239713a627054448c9fbfc7af84cc2fa5e8a0ed Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 11 Dec 2024 17:51:29 +0000 Subject: [PATCH 39/69] tokens serialization tests --- rs/ledger_suite/common/ledger_core/src/tokens.rs | 3 +++ .../common/ledger_core/src/tokens/tests.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 rs/ledger_suite/common/ledger_core/src/tokens/tests.rs diff --git a/rs/ledger_suite/common/ledger_core/src/tokens.rs b/rs/ledger_suite/common/ledger_core/src/tokens.rs index f4b03b56324..1693324ce1b 100644 --- a/rs/ledger_suite/common/ledger_core/src/tokens.rs +++ b/rs/ledger_suite/common/ledger_core/src/tokens.rs @@ -7,6 +7,9 @@ use std::borrow::Cow; use std::fmt; use std::fmt::Debug; +#[cfg(test)] +mod tests; + /// Performs addition that returns `None` instead of wrapping around on /// overflow. /// diff --git a/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs b/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs new file mode 100644 index 00000000000..d8f5426c39f --- /dev/null +++ b/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs @@ -0,0 +1,14 @@ +use crate::tokens::Tokens; +use ic_stable_structures::Storable; +use proptest::prelude::{any, prop_assert_eq, proptest}; + +#[test] +fn timestamp_serialization() { + proptest!(|(e8s in any::())| { + let tokens = Tokens { + e8s, + }; + let new_tokens = Tokens::from_bytes(tokens.to_bytes()); + prop_assert_eq!(new_tokens, tokens); + }) +} From e6acc169f6eaa5b97e19401d768b42e4a321a76f Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 10:54:01 +0000 Subject: [PATCH 40/69] small refactor --- rs/ledger_suite/common/ledger_core/src/tokens/tests.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs b/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs index d8f5426c39f..3379b49de9a 100644 --- a/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs +++ b/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs @@ -5,9 +5,7 @@ use proptest::prelude::{any, prop_assert_eq, proptest}; #[test] fn timestamp_serialization() { proptest!(|(e8s in any::())| { - let tokens = Tokens { - e8s, - }; + let tokens = Tokens { e8s }; let new_tokens = Tokens::from_bytes(tokens.to_bytes()); prop_assert_eq!(new_tokens, tokens); }) From 0325b46f362823c20bb723fa4ecd016a77c132df Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 14:19:49 +0000 Subject: [PATCH 41/69] add some tests --- WORKSPACE.bazel | 4 ++++ mainnet-canisters.json | 8 +++++++ rs/ledger_suite/icp/ledger/BUILD.bazel | 4 ++++ rs/ledger_suite/icp/ledger/tests/tests.rs | 29 +++++++++++++++++++++-- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 5294d5c1e6f..100120d39f0 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -17,6 +17,8 @@ canisters( "registry": "registry-canister.wasm.gz", "governance": "governance-canister.wasm.gz", "ledger": "ledger-canister_notify-method.wasm.gz", + "ledger_v1": "ledger-canister_notify-method.wasm.gz", + "ledger_v2": "ledger-canister_notify-method.wasm.gz", "archive": "ledger-archive-node-canister.wasm.gz", "index": "ic-icp-index-canister.wasm.gz", "root": "root-canister.wasm.gz", @@ -47,6 +49,8 @@ canisters( "registry": "mainnet_nns_registry_canister", "governance": "mainnet_nns_governance_canister", "ledger": "mainnet_icp_ledger_canister", + "ledger_v1": "mainnet_icp_ledger_canister-v1", + "ledger_v2": "mainnet_icp_ledger_canister-v2", "archive": "mainnet_icp_ledger-archive-node-canister", "index": "mainnet_icp_index_canister", "root": "mainnet_nns_root-canister", diff --git a/mainnet-canisters.json b/mainnet-canisters.json index ef14f1cc45d..41915627879 100644 --- a/mainnet-canisters.json +++ b/mainnet-canisters.json @@ -60,6 +60,14 @@ "sha256": "3cc807d6c602be5041635c03522b99049d91c2a2ed18cb87251d5611ef779c98" }, "ledger": { + "rev": "b006ae9934f2622d1db73a25dea7515d190a93e7", + "sha256": "15dbbd7a050f565017796814531a90d4d155b67dc14ef260440895a86fa22223" + }, + "ledger_v1": { + "rev": "6dcfafb491092704d374317d9a72a7ad2475d7c9", + "sha256": "4fe38a91a3130e9d8b39e3413ae3b3f46c40d3fbd507df1b6092f962d970a7ea" + }, + "ledger_v2": { "rev": "dac2f36f96d7549d82fa8e3c714979255ce57afd", "sha256": "50c05fd687883fe788c0bb91996de358d8f856ba56088c6ff47767ea853001d7" }, diff --git a/rs/ledger_suite/icp/ledger/BUILD.bazel b/rs/ledger_suite/icp/ledger/BUILD.bazel index 0d9bea50cb9..fb6d2de14ae 100644 --- a/rs/ledger_suite/icp/ledger/BUILD.bazel +++ b/rs/ledger_suite/icp/ledger/BUILD.bazel @@ -118,12 +118,16 @@ rust_ic_test( ":ledger-canister-wasm-allowance-getter", ":ledger-canister-wasm-low-limits", ":ledger-canister-wasm-next-version", + "@mainnet_icp_ledger_canister-v1//file", + "@mainnet_icp_ledger_canister-v2//file", "@mainnet_icp_ledger_canister//file", ], env = { "RUST_TEST_THREADS": "4", "CARGO_MANIFEST_DIR": "rs/ledger_suite/icp/ledger", "ICP_LEDGER_DEPLOYED_VERSION_WASM_PATH": "$(rootpath @mainnet_icp_ledger_canister//file)", + "ICP_LEDGER_DEPLOYED_VERSION_V1_WASM_PATH": "$(rootpath @mainnet_icp_ledger_canister-v1//file)", + "ICP_LEDGER_DEPLOYED_VERSION_V2_WASM_PATH": "$(rootpath @mainnet_icp_ledger_canister-v2//file)", "LEDGER_CANISTER_WASM_PATH": "$(rootpath :ledger-canister-wasm)", "LEDGER_CANISTER_ALLOWANCE_GETTER_WASM_PATH": "$(rootpath :ledger-canister-wasm-allowance-getter)", "LEDGER_CANISTER_NEXT_VERSION_WASM_PATH": "$(rootpath :ledger-canister-wasm-next-version)", diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 40d4cddef55..121bb09b67f 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -58,6 +58,14 @@ fn ledger_wasm_mainnet() -> Vec { std::fs::read(std::env::var("ICP_LEDGER_DEPLOYED_VERSION_WASM_PATH").unwrap()).unwrap() } +fn ledger_wasm_mainnet_v1() -> Vec { + std::fs::read(std::env::var("ICP_LEDGER_DEPLOYED_VERSION_V1_WASM_PATH").unwrap()).unwrap() +} + +fn ledger_wasm_mainnet_v2() -> Vec { + std::fs::read(std::env::var("ICP_LEDGER_DEPLOYED_VERSION_V2_WASM_PATH").unwrap()).unwrap() +} + fn ledger_wasm_allowance_getter() -> Vec { ic_test_utilities_load_wasm::load_wasm( std::env::var("CARGO_MANIFEST_DIR").unwrap(), @@ -1231,8 +1239,16 @@ fn test_block_transformation() { } #[test] -fn test_upgrade_serialization() { - let ledger_wasm_mainnet = ledger_wasm_mainnet(); +fn test_upgrade_serialization_from_master() { + test_upgrade_serialization(ledger_wasm_mainnet()); +} + +#[test] +fn test_upgrade_serialization_from_v2() { + test_upgrade_serialization(ledger_wasm_mainnet_v2()); +} + +fn test_upgrade_serialization(ledger_wasm_mainnet: Vec) { let ledger_wasm_current = ledger_wasm(); let minter = Arc::new(minter_identity()); @@ -1341,6 +1357,15 @@ fn test_metrics_while_migrating() { ); } +#[test] +fn test_upgrade_from_v1_not_possible() { + ic_ledger_suite_state_machine_tests::test_upgrade_from_v1_not_possible( + ledger_wasm_mainnet_v1(), + ledger_wasm(), + encode_init_args, + ); +} + #[test] fn test_approve_smoke() { ic_ledger_suite_state_machine_tests::test_approve_smoke(ledger_wasm(), encode_init_args); From 2ab57f1f4bd03ec480b947ed8293ed21f8ca8c9f Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 14:24:45 +0000 Subject: [PATCH 42/69] refactor tests --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index 8437d85b6fa..8a0a9dd7b04 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -468,24 +468,15 @@ fn test_block_transformation() { #[test] fn icrc1_test_upgrade_serialization_from_mainnet() { - let minter = Arc::new(minter_identity()); - let builder = LedgerInitArgsBuilder::with_symbol_and_name(TOKEN_SYMBOL, TOKEN_NAME) - .with_minting_account(minter.sender().unwrap()) - .with_transfer_fee(FEE); - let init_args = Encode!(&LedgerArgument::Init(builder.build())).unwrap(); - let upgrade_args = Encode!(&LedgerArgument::Upgrade(None)).unwrap(); - ic_ledger_suite_state_machine_tests::test_upgrade_serialization::( - ledger_mainnet_wasm(), - ledger_wasm(), - init_args, - upgrade_args, - minter, - true, - ); + icrc1_test_upgrade_serialization(ledger_mainnet_wasm()); } #[test] fn icrc1_test_upgrade_serialization_from_v2() { + icrc1_test_upgrade_serialization(ledger_mainnet_v2_wasm()); +} + +fn icrc1_test_upgrade_serialization(ledger_mainnet_wasm: Vec) { let minter = Arc::new(minter_identity()); let builder = LedgerInitArgsBuilder::with_symbol_and_name(TOKEN_SYMBOL, TOKEN_NAME) .with_minting_account(minter.sender().unwrap()) @@ -493,7 +484,7 @@ fn icrc1_test_upgrade_serialization_from_v2() { let init_args = Encode!(&LedgerArgument::Init(builder.build())).unwrap(); let upgrade_args = Encode!(&LedgerArgument::Upgrade(None)).unwrap(); ic_ledger_suite_state_machine_tests::test_upgrade_serialization::( - ledger_mainnet_v2_wasm(), + ledger_mainnet_wasm, ledger_wasm(), init_args, upgrade_args, From 838835346ebcec9754959058c50c9c3a82306cd6 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 14:45:50 +0000 Subject: [PATCH 43/69] more tests --- rs/ledger_suite/icp/ledger/tests/tests.rs | 57 ++++++++++++++++++++--- rs/ledger_suite/tests/sm-tests/src/lib.rs | 2 +- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 121bb09b67f..7681ac595c7 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1274,7 +1274,7 @@ fn test_upgrade_serialization(ledger_wasm_mainnet: Vec) { } #[test] -fn test_multi_step_migration() { +fn test_multi_step_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration( ledger_wasm_mainnet(), ledger_wasm_low_instruction_limits(), @@ -1282,6 +1282,15 @@ fn test_multi_step_migration() { ); } +#[test] +fn test_multi_step_migration_from_v2() { + ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration( + ledger_wasm_mainnet_v2(), + ledger_wasm_low_instruction_limits(), + encode_init_args, + ); +} + #[test] fn test_downgrade_from_incompatible_version() { ic_ledger_suite_state_machine_tests::test_downgrade_from_incompatible_version( @@ -1294,7 +1303,16 @@ fn test_downgrade_from_incompatible_version() { } #[test] -fn test_stable_migration_endpoints_disabled() { +fn test_stable_migration_endpoints_disabled_from_mainnet() { + test_stable_migration_endpoints_disabled(ledger_wasm_mainnet()); +} + +#[test] +fn test_stable_migration_endpoints_disabled_from_v2() { + test_stable_migration_endpoints_disabled(ledger_wasm_mainnet_v2()); +} + +fn test_stable_migration_endpoints_disabled(ledger_wasm_mainnet: Vec) { let send_args = SendArgs { memo: icp_ledger::Memo::default(), amount: Tokens::from_e8s(1), @@ -1319,7 +1337,7 @@ fn test_stable_migration_endpoints_disabled() { .unwrap(); ic_ledger_suite_state_machine_tests::icrc1_test_stable_migration_endpoints_disabled( - ledger_wasm_mainnet(), + ledger_wasm_mainnet, ledger_wasm_low_instruction_limits(), encode_init_args, vec![ @@ -1331,7 +1349,7 @@ fn test_stable_migration_endpoints_disabled() { } #[test] -fn test_incomplete_migration() { +fn test_incomplete_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::test_incomplete_migration( ledger_wasm_mainnet(), ledger_wasm_low_instruction_limits(), @@ -1340,7 +1358,16 @@ fn test_incomplete_migration() { } #[test] -fn test_incomplete_migration_to_current() { +fn test_incomplete_migration_from_v2() { + ic_ledger_suite_state_machine_tests::test_incomplete_migration( + ledger_wasm_mainnet_v2(), + ledger_wasm_low_instruction_limits(), + encode_init_args, + ); +} + +#[test] +fn test_incomplete_migration_to_current_from_mainnet() { ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( ledger_wasm_mainnet(), ledger_wasm_low_instruction_limits(), @@ -1349,7 +1376,16 @@ fn test_incomplete_migration_to_current() { } #[test] -fn test_metrics_while_migrating() { +fn test_incomplete_migration_to_current_from_v2() { + ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( + ledger_wasm_mainnet_v2(), + ledger_wasm_low_instruction_limits(), + encode_init_args, + ); +} + +#[test] +fn test_metrics_while_migrating_from_mainnet() { ic_ledger_suite_state_machine_tests::test_metrics_while_migrating( ledger_wasm_mainnet(), ledger_wasm_low_instruction_limits(), @@ -1357,6 +1393,15 @@ fn test_metrics_while_migrating() { ); } +#[test] +fn test_metrics_while_migrating_from_v2() { + ic_ledger_suite_state_machine_tests::test_metrics_while_migrating( + ledger_wasm_mainnet_v2(), + ledger_wasm_low_instruction_limits(), + encode_init_args, + ); +} + #[test] fn test_upgrade_from_v1_not_possible() { ic_ledger_suite_state_machine_tests::test_upgrade_from_v1_not_possible( diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 7cd05e194fc..3d1c01e3fe2 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -2759,7 +2759,7 @@ pub fn icrc1_test_stable_migration_endpoints_disabled( send_approval(&env, canister_id, account.owner, &approve_args).expect("approval failed"); } - for i in 2..30 { + for i in 2..40 { let to = Account::from(PrincipalId::new_user_test_id(i).0); transfer(&env, canister_id, account, to, 100).expect("failed to transfer funds"); } From a35b41791321bd45235482d8f0a9ed2ef8433ff3 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 15:17:20 +0000 Subject: [PATCH 44/69] remove max accounts from ledger and tests --- .../common/ledger_canister_core/src/ledger.rs | 7 ------ rs/ledger_suite/icp/ledger.did | 2 -- rs/ledger_suite/icp/ledger/src/lib.rs | 23 +++-------------- rs/ledger_suite/icp/ledger/src/main.rs | 8 ------ rs/ledger_suite/icp/ledger/tests/tests.rs | 4 --- rs/ledger_suite/icp/src/lib.rs | 25 ------------------- rs/ledger_suite/icrc1/ledger/src/lib.rs | 8 ------ rs/ledger_suite/tests/sm-tests/src/lib.rs | 11 -------- 8 files changed, 4 insertions(+), 84 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index e20c09c7409..a97b5af638e 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -154,13 +154,6 @@ pub trait LedgerData: LedgerContext { /// The maximum number of transactions that we attempt to purge in one go. fn max_transactions_to_purge(&self) -> usize; - /// The maximum size of the balances map. - fn max_number_of_accounts(&self) -> usize; - - /// How many accounts with lowest balances to purge when the number of accounts exceeds - /// [LedgerData::max_number_of_accounts]. - fn accounts_overflow_trim_quantity(&self) -> usize; - // Token configuration /// Token name (e.g., Bitcoin). diff --git a/rs/ledger_suite/icp/ledger.did b/rs/ledger_suite/icp/ledger.did index a4778eb2446..7466333461c 100644 --- a/rs/ledger_suite/icp/ledger.did +++ b/rs/ledger_suite/icp/ledger.did @@ -302,8 +302,6 @@ type InitArgs = record { token_symbol: opt text; token_name: opt text; feature_flags : opt FeatureFlags; - maximum_number_of_accounts : opt nat64; - accounts_overflow_trim_quantity: opt nat64; }; type Icrc1BlockIndex = nat; diff --git a/rs/ledger_suite/icp/ledger/src/lib.rs b/rs/ledger_suite/icp/ledger/src/lib.rs index de47c6092dd..ed20d4cefbc 100644 --- a/rs/ledger_suite/icp/ledger/src/lib.rs +++ b/rs/ledger_suite/icp/ledger/src/lib.rs @@ -194,8 +194,9 @@ pub struct Ledger { #[serde(default)] stable_approvals: AllowanceTable, pub blockchain: Blockchain, - // A cap on the maximum number of accounts. + // DEPRECETAD, UNUSED: A cap on the maximum number of accounts. pub maximum_number_of_accounts: usize, + // DEPRECETAD, UNUSED: // When maximum number of accounts is exceeded, a specified number of // accounts with lowest balances are removed. accounts_overflow_trim_quantity: usize, @@ -287,14 +288,6 @@ impl LedgerData for Ledger { Self::MAX_TRANSACTIONS_TO_PURGE } - fn max_number_of_accounts(&self) -> usize { - self.maximum_number_of_accounts - } - - fn accounts_overflow_trim_quantity(&self) -> usize { - self.accounts_overflow_trim_quantity - } - fn token_name(&self) -> &str { &self.token_name } @@ -346,8 +339,8 @@ impl Default for Ledger { stable_approvals: Default::default(), balances: LedgerBalances::default(), blockchain: Blockchain::default(), - maximum_number_of_accounts: 28_000_000, - accounts_overflow_trim_quantity: 100_000, + maximum_number_of_accounts: 0, + accounts_overflow_trim_quantity: 0, minting_account_id: None, icrc1_minting_account: None, blocks_notified: IntMap::new(), @@ -463,8 +456,6 @@ impl Ledger { token_symbol: Option, token_name: Option, feature_flags: Option, - maximum_number_of_accounts: Option, - accounts_overflow_trim_quantity: Option, ) { self.token_symbol = token_symbol.unwrap_or_else(|| "ICP".to_string()); self.token_name = token_name.unwrap_or_else(|| "Internet Computer".to_string()); @@ -492,12 +483,6 @@ impl Ledger { if let Some(feature_flags) = feature_flags { self.feature_flags = feature_flags; } - if let Some(maximum_number_of_accounts) = maximum_number_of_accounts { - self.maximum_number_of_accounts = maximum_number_of_accounts; - } - if let Some(accounts_overflow_trim_quantity) = accounts_overflow_trim_quantity { - self.accounts_overflow_trim_quantity = accounts_overflow_trim_quantity; - } } pub fn change_notification_state( diff --git a/rs/ledger_suite/icp/ledger/src/main.rs b/rs/ledger_suite/icp/ledger/src/main.rs index 7107be238ab..e0d3463b830 100644 --- a/rs/ledger_suite/icp/ledger/src/main.rs +++ b/rs/ledger_suite/icp/ledger/src/main.rs @@ -113,8 +113,6 @@ fn init( token_symbol: Option, token_name: Option, feature_flags: Option, - maximum_number_of_accounts: Option, - accounts_overflow_trim_quantity: Option, ) { print(format!( "[ledger] init(): minting account is {}", @@ -131,8 +129,6 @@ fn init( token_symbol, token_name, feature_flags, - maximum_number_of_accounts, - accounts_overflow_trim_quantity, ); match max_message_size_bytes { None => { @@ -712,8 +708,6 @@ fn canister_init(arg: LedgerCanisterPayload) { arg.token_symbol, arg.token_name, arg.feature_flags, - arg.maximum_number_of_accounts, - arg.accounts_overflow_trim_quantity, ), LedgerCanisterPayload::Upgrade(_) => { trap_with("Cannot initialize the canister with an Upgrade argument. Please provide an Init argument."); @@ -745,8 +739,6 @@ fn main() { arg.token_symbol, arg.token_name, arg.feature_flags, - arg.maximum_number_of_accounts, - arg.accounts_overflow_trim_quantity, ), Err(old_err) => trap_with(&format!("Unable to decode init argument.\nDecode as new init returned the error {}\nDecode as old init returned the error {}", new_err, old_err)) diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 7681ac595c7..f10ee607ef9 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -98,8 +98,6 @@ fn encode_init_args( .transfer_fee(Tokens::try_from(args.transfer_fee).unwrap()) .token_symbol_and_name(&args.token_symbol, &args.token_name) .feature_flags(FeatureFlags { icrc2: true }) - .maximum_number_of_accounts(args.maximum_number_of_accounts) - .accounts_overflow_trim_quantity(args.accounts_overflow_trim_quantity) .build() .unwrap() } @@ -521,8 +519,6 @@ fn check_old_init() { token_symbol: Some("ICP".into()), token_name: Some("Internet Computer".into()), feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, }) .unwrap(); env.install_canister(ledger_wasm(), old_init, None) diff --git a/rs/ledger_suite/icp/src/lib.rs b/rs/ledger_suite/icp/src/lib.rs index bb614749a81..236021f78f5 100644 --- a/rs/ledger_suite/icp/src/lib.rs +++ b/rs/ledger_suite/icp/src/lib.rs @@ -474,8 +474,6 @@ pub struct InitArgs { pub token_symbol: Option, pub token_name: Option, pub feature_flags: Option, - pub maximum_number_of_accounts: Option, - pub accounts_overflow_trim_quantity: Option, } impl LedgerCanisterInitPayload { @@ -508,8 +506,6 @@ pub struct LedgerCanisterInitPayloadBuilder { token_symbol: Option, token_name: Option, feature_flags: Option, - maximum_number_of_accounts: Option, - accounts_overflow_trim_quantity: Option, } impl LedgerCanisterInitPayloadBuilder { @@ -526,8 +522,6 @@ impl LedgerCanisterInitPayloadBuilder { token_symbol: None, token_name: None, feature_flags: None, - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, } } @@ -582,23 +576,6 @@ impl LedgerCanisterInitPayloadBuilder { self } - pub fn maximum_number_of_accounts(mut self, maximum_number_of_accounts: Option) -> Self { - if let Some(maximum_number_of_accounts) = maximum_number_of_accounts { - self.maximum_number_of_accounts = Some(maximum_number_of_accounts as usize); - } - self - } - - pub fn accounts_overflow_trim_quantity( - mut self, - accounts_overflow_trim_quantity: Option, - ) -> Self { - if let Some(accounts_overflow_trim_quantity) = accounts_overflow_trim_quantity { - self.accounts_overflow_trim_quantity = Some(accounts_overflow_trim_quantity as usize); - } - self - } - pub fn build(self) -> Result { let minting_account = self .minting_account @@ -632,8 +609,6 @@ impl LedgerCanisterInitPayloadBuilder { token_symbol: self.token_symbol, token_name: self.token_name, feature_flags: self.feature_flags, - maximum_number_of_accounts: self.maximum_number_of_accounts, - accounts_overflow_trim_quantity: self.accounts_overflow_trim_quantity, }, ))) } diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 2bb483f447e..200d85440e3 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -786,14 +786,6 @@ impl LedgerData for Ledger { MAX_TRANSACTIONS_TO_PURGE } - fn max_number_of_accounts(&self) -> usize { - self.maximum_number_of_accounts - } - - fn accounts_overflow_trim_quantity(&self) -> usize { - self.accounts_overflow_trim_quantity - } - fn token_name(&self) -> &str { &self.token_name } diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 3d1c01e3fe2..19490d6309e 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -101,8 +101,6 @@ pub struct InitArgs { pub metadata: Vec<(String, Value)>, pub archive_options: ArchiveOptions, pub feature_flags: Option, - pub maximum_number_of_accounts: Option, - pub accounts_overflow_trim_quantity: Option, } #[derive(Clone, Eq, PartialEq, Debug, CandidType)] @@ -119,7 +117,6 @@ pub struct UpgradeArgs { pub transfer_fee: Option, pub change_fee_collector: Option, pub feature_flags: Option, - pub accounts_overflow_trim_quantity: Option, pub change_archive_options: Option, } @@ -894,8 +891,6 @@ fn init_args(initial_balances: Vec<(Account, u64)>) -> InitArgs { max_transactions_per_response: None, }, feature_flags: Some(FeatureFlags { icrc2: true }), - maximum_number_of_accounts: None, - accounts_overflow_trim_quantity: None, } } @@ -1666,8 +1661,6 @@ pub fn test_archive_controllers(ledger_wasm: Vec) { max_transactions_per_response: None, }, feature_flags: args.feature_flags, - maximum_number_of_accounts: args.maximum_number_of_accounts, - accounts_overflow_trim_quantity: args.accounts_overflow_trim_quantity, }) } @@ -1696,8 +1689,6 @@ pub fn test_archive_no_additional_controllers(ledger_wasm: Vec) { max_transactions_per_response: None, }, feature_flags: args.feature_flags, - maximum_number_of_accounts: args.maximum_number_of_accounts, - accounts_overflow_trim_quantity: args.accounts_overflow_trim_quantity, }) } @@ -1731,8 +1722,6 @@ pub fn test_archive_duplicate_controllers(ledger_wasm: Vec) { max_transactions_per_response: None, }, feature_flags: args.feature_flags, - maximum_number_of_accounts: args.maximum_number_of_accounts, - accounts_overflow_trim_quantity: args.accounts_overflow_trim_quantity, }) } let p100 = PrincipalId::new_user_test_id(100); From a5847ff9410b980d638f42ce7f8cbd60d84536d8 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 15:26:13 +0000 Subject: [PATCH 45/69] remove default values for max accounts --- rs/ledger_suite/icrc1/ledger/src/lib.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 267e9e19ae5..ee7d2fc00bf 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -62,11 +62,9 @@ use std::ops::DerefMut; use std::time::Duration; const TRANSACTION_WINDOW: Duration = Duration::from_secs(24 * 60 * 60); -const MAX_ACCOUNTS: usize = 28_000_000; /// The maximum number of transactions the ledger should return for a single /// get_transactions request. const MAX_TRANSACTIONS_PER_REQUEST: usize = 2_000; -const ACCOUNTS_OVERFLOW_TRIM_QUANTITY: usize = 100_000; const MAX_TRANSACTIONS_IN_WINDOW: usize = 3_000_000; const MAX_TRANSACTIONS_TO_PURGE: usize = 100_000; #[allow(dead_code)] @@ -577,23 +575,17 @@ pub struct Ledger { #[serde(default)] feature_flags: FeatureFlags, - #[serde(default = "default_maximum_number_of_accounts")] + // DEPRECATED + #[serde(default)] maximum_number_of_accounts: usize, - #[serde(default = "default_accounts_overflow_trim_quantity")] + // DEPRECATED + #[serde(default)] accounts_overflow_trim_quantity: usize, #[serde(default = "default_ledger_version")] pub ledger_version: u64, } -fn default_maximum_number_of_accounts() -> usize { - MAX_ACCOUNTS -} - -fn default_accounts_overflow_trim_quantity() -> usize { - ACCOUNTS_OVERFLOW_TRIM_QUANTITY -} - fn default_ledger_version() -> u64 { LEDGER_VERSION } @@ -672,8 +664,8 @@ impl Ledger { .collect(), max_memo_length: max_memo_length.unwrap_or(DEFAULT_MAX_MEMO_LENGTH), feature_flags: feature_flags.unwrap_or_default(), - maximum_number_of_accounts: MAX_ACCOUNTS, - accounts_overflow_trim_quantity: ACCOUNTS_OVERFLOW_TRIM_QUANTITY, + maximum_number_of_accounts: 0, + accounts_overflow_trim_quantity: 0, ledger_version: LEDGER_VERSION, }; From e52cc78ce0c7a12e492497ccb65638df81ecd470 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 15:29:33 +0000 Subject: [PATCH 46/69] build fix --- rs/ledger_suite/icp/ledger/src/tests.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/src/tests.rs b/rs/ledger_suite/icp/ledger/src/tests.rs index 80d0ac79305..a3bf66c0566 100644 --- a/rs/ledger_suite/icp/ledger/src/tests.rs +++ b/rs/ledger_suite/icp/ledger/src/tests.rs @@ -200,8 +200,6 @@ fn serialize() { Some("ICP".into()), Some("icp".into()), None, - None, - None, ); let txn = Transaction::new( @@ -540,8 +538,6 @@ fn get_blocks_returns_correct_blocks() { Some("ICP".into()), Some("icp".into()), None, - None, - None, ); for i in 0..10 { @@ -605,8 +601,6 @@ fn test_purge() { Some("ICP".into()), Some("icp".into()), None, - None, - None, ); let little_later = genesis + Duration::from_millis(1); From 76d31318b2be39cd414e12a46ca0acba97964a74 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 12 Dec 2024 15:31:44 +0000 Subject: [PATCH 47/69] fix comments --- rs/ledger_suite/icp/ledger/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/src/lib.rs b/rs/ledger_suite/icp/ledger/src/lib.rs index ed20d4cefbc..98a27c87ea5 100644 --- a/rs/ledger_suite/icp/ledger/src/lib.rs +++ b/rs/ledger_suite/icp/ledger/src/lib.rs @@ -194,11 +194,9 @@ pub struct Ledger { #[serde(default)] stable_approvals: AllowanceTable, pub blockchain: Blockchain, - // DEPRECETAD, UNUSED: A cap on the maximum number of accounts. + // DEPRECATED pub maximum_number_of_accounts: usize, - // DEPRECETAD, UNUSED: - // When maximum number of accounts is exceeded, a specified number of - // accounts with lowest balances are removed. + // DEPRECATED accounts_overflow_trim_quantity: usize, pub minting_account_id: Option, pub icrc1_minting_account: Option, From 49e7bb82332904ebfa90623a92d6dbfb3a2dabf9 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 13 Dec 2024 13:52:51 +0000 Subject: [PATCH 48/69] update ICRC v3 git commit and wasm hash --- mainnet-canisters.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainnet-canisters.json b/mainnet-canisters.json index bae9a3cb0c6..46a3ae6e588 100644 --- a/mainnet-canisters.json +++ b/mainnet-canisters.json @@ -12,8 +12,8 @@ "sha256": "67b5f0bf128e801adf4a959ea26c3c9ca0cd399940e169a26a2eb237899a94dd" }, "ck_btc_ledger": { - "rev": "8d726cc67a8ec83b55e5dc6305f49c1e4304d6dd", - "sha256": "d12febb9b719c2bbf44e18bccc9fd027a1d2e823622d0dc8b524c8a43bd4f698" + "rev": "2190613d3b5bcd9b74c382b22d151580b8ac271a", + "sha256": "25071c2c55ad4571293e00d8e277f442aec7aed88109743ac52df3125209ff45" }, "ck_btc_ledger_v1": { "rev": "d4ee25b0865e89d3eaac13a60f0016d5e3296b31", From 563eafe31b1a2d77a276d9299330e4769958a130 Mon Sep 17 00:00:00 2001 From: maciejdfinity <122265298+maciejdfinity@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:54:53 +0100 Subject: [PATCH 49/69] Update rs/ledger_suite/icrc1/ledger/src/main.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mathias Björkqvist --- rs/ledger_suite/icrc1/ledger/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index f7aacbfa47d..69f2898ee6e 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -239,7 +239,7 @@ fn post_upgrade(args: Option) { if upgrade_from_version < 2 { set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); - log_message(format!("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data.").as_str()); + log_message(format!("Upgrading from version {upgrade_from_version} which does not store balances in stable structures, clearing stable balances data.").as_str()); clear_stable_balances_data(); Access::with_ledger_mut(|ledger| { ledger.copy_token_pool(); From 91a092e047ddb90f4c5c89c996c9ba16efef14c2 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 18 Dec 2024 13:39:42 +0000 Subject: [PATCH 50/69] fix sm tests --- rs/ledger_suite/icp/ledger/tests/tests.rs | 1 + rs/ledger_suite/icrc1/ledger/tests/tests.rs | 3 ++- rs/ledger_suite/tests/sm-tests/src/lib.rs | 28 +++++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index b3362beb36a..4b7573de082 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1250,6 +1250,7 @@ fn test_upgrade_serialization() { upgrade_args, minter, false, + false, ); } diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index 0f980d83139..ab586ece141 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -490,6 +490,7 @@ fn icrc1_test_upgrade_serialization(ledger_mainnet_wasm: Vec) { upgrade_args, minter, true, + true, ); } @@ -519,7 +520,7 @@ fn icrc1_test_downgrade_from_incompatible_version() { ledger_wasm_nextledgerversion(), ledger_wasm(), encode_init_args, - true, + false, ); } diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index d76f88d0835..9cd11d9b96d 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -2413,6 +2413,7 @@ pub fn test_upgrade_serialization( upgrade_args: Vec, minter: Arc, verify_blocks: bool, + mainnet_on_prev_version: bool, ) where Tokens: TokensType + Default + std::fmt::Display + From, { @@ -2470,20 +2471,33 @@ pub fn test_upgrade_serialization( }; // Test if the old serialized approvals and balances are correctly deserialized - // TODO: Expected migration steps should be 1 again in FI-1440. - // test_upgrade(ledger_wasm_current.clone(), 1); + let expected_steps = if mainnet_on_prev_version { 1 } else { 0 }; + test_upgrade(ledger_wasm_current.clone(), expected_steps); // Test the new wasm serialization test_upgrade(ledger_wasm_current.clone(), 0); // Test deserializing from memory manager test_upgrade(ledger_wasm_current.clone(), 0); - // Downgrade to mainnet should succeed since they are both the same version wrt. - // migration to stable structures. - env.upgrade_canister( + // Downgrade to mainnet if possible. + match env.upgrade_canister( ledger_id, ledger_wasm_mainnet.clone(), Encode!(&LedgerArgument::Upgrade(None)).unwrap(), - ) - .expect("Downgrading to mainnet should succeed"); + ) { + Ok(_) => { + if mainnet_on_prev_version { + panic!("Upgrade from future ledger version should fail!") + } + } + Err(e) => { + if mainnet_on_prev_version { + assert!(e + .description() + .contains("Trying to downgrade from incompatible version")) + } else { + panic!("Upgrade to mainnet should succeed!") + } + } + }; if verify_blocks { // This will also verify the ledger blocks. // The current implementation of the InMemoryLedger cannot get blocks From 54bf39006523a25a39ebbdd07df7fa1b75b4551e Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 18 Dec 2024 13:43:43 +0000 Subject: [PATCH 51/69] fix upgrade downgrade tests --- rs/ledger_suite/icrc1/tests/upgrade_downgrade.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/rs/ledger_suite/icrc1/tests/upgrade_downgrade.rs b/rs/ledger_suite/icrc1/tests/upgrade_downgrade.rs index db8191ea320..d44725258db 100644 --- a/rs/ledger_suite/icrc1/tests/upgrade_downgrade.rs +++ b/rs/ledger_suite/icrc1/tests/upgrade_downgrade.rs @@ -77,12 +77,20 @@ fn should_upgrade_and_downgrade_ledger_canister_suite() { ) .unwrap(); - env.upgrade_canister( + match env.upgrade_canister( ledger_id, ledger_mainnet_wasm(), Encode!(&ledger_upgrade_arg).unwrap(), - ) - .unwrap(); + ) { + Ok(_) => { + panic!("Upgrade to mainnet should fail!") + } + Err(e) => { + assert!(e + .description() + .contains("Trying to downgrade from incompatible version")) + } + }; } fn default_archive_options() -> ArchiveOptions { From 892b03c784fe221e764774e90fbf0f841e4e8721 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 18 Dec 2024 13:47:55 +0000 Subject: [PATCH 52/69] reenable ignored tests --- rs/ledger_suite/icrc1/ledger/tests/tests.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rs/ledger_suite/icrc1/ledger/tests/tests.rs b/rs/ledger_suite/icrc1/ledger/tests/tests.rs index ab586ece141..e3b0fee8020 100644 --- a/rs/ledger_suite/icrc1/ledger/tests/tests.rs +++ b/rs/ledger_suite/icrc1/ledger/tests/tests.rs @@ -494,7 +494,6 @@ fn icrc1_test_upgrade_serialization(ledger_mainnet_wasm: Vec) { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn icrc1_test_multi_step_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration( @@ -524,7 +523,6 @@ fn icrc1_test_downgrade_from_incompatible_version() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn icrc1_test_stable_migration_endpoints_disabled_from_mainnet() { ic_ledger_suite_state_machine_tests::icrc1_test_stable_migration_endpoints_disabled( @@ -535,7 +533,6 @@ fn icrc1_test_stable_migration_endpoints_disabled_from_mainnet() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn icrc1_test_stable_migration_endpoints_disabled_from_v2() { ic_ledger_suite_state_machine_tests::icrc1_test_stable_migration_endpoints_disabled( @@ -555,7 +552,6 @@ fn icrc1_test_incomplete_migration_from_mainnet() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn icrc1_test_incomplete_migration_from_v2() { ic_ledger_suite_state_machine_tests::test_incomplete_migration( @@ -574,7 +570,6 @@ fn icrc1_test_incomplete_migration_to_current_from_mainnet() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn icrc1_test_incomplete_migration_to_current_from_v2() { ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( @@ -593,7 +588,6 @@ fn icrc1_test_migration_resumes_from_frozen_from_mainnet() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn icrc1_test_migration_resumes_from_frozen_from_v2() { ic_ledger_suite_state_machine_tests::test_migration_resumes_from_frozen( From 49ebc9945572d04d7d6fddb996903ac4e6705bc3 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 18 Dec 2024 14:21:54 +0000 Subject: [PATCH 53/69] fix golden state tests --- .../tests/golden_state_upgrade_downgrade.rs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/rs/ledger_suite/icrc1/tests/golden_state_upgrade_downgrade.rs b/rs/ledger_suite/icrc1/tests/golden_state_upgrade_downgrade.rs index 7b97715f99d..bfa0c0d13f3 100644 --- a/rs/ledger_suite/icrc1/tests/golden_state_upgrade_downgrade.rs +++ b/rs/ledger_suite/icrc1/tests/golden_state_upgrade_downgrade.rs @@ -14,7 +14,7 @@ use ic_ledger_suite_state_machine_tests::{ wait_ledger_ready, TransactionGenerationParameters, }; use ic_nns_test_utils_golden_nns_state::new_state_machine_with_golden_fiduciary_state_or_panic; -use ic_state_machine_tests::{StateMachine, UserError}; +use ic_state_machine_tests::{ErrorCode, StateMachine, UserError}; use icrc_ledger_types::icrc1::account::Account; use lazy_static::lazy_static; use std::str::FromStr; @@ -351,18 +351,19 @@ impl LedgerSuiteConfig { // Upgrade each canister twice to exercise pre-upgrade self.upgrade_index_or_panic(state_machine, &self.mainnet_wasms.index_wasm); self.upgrade_index_or_panic(state_machine, &self.mainnet_wasms.index_wasm); - self.upgrade_ledger( - state_machine, - &self.mainnet_wasms.ledger_wasm, - ExpectMigration::No, - ) - .expect("should downgrade to mainnet ledger version"); - self.upgrade_ledger( + match self.upgrade_ledger( state_machine, &self.mainnet_wasms.ledger_wasm, ExpectMigration::No, - ) - .expect("should downgrade to mainnet ledger version"); + ) { + Ok(_) => { + panic!("should not successfully downgrade ledger"); + } + Err(user_error) => user_error.assert_contains( + ErrorCode::CanisterCalledTrap, + "Trying to downgrade from incompatible version", + ), + } self.upgrade_archives_or_panic(state_machine, &self.mainnet_wasms.archive_wasm); self.upgrade_archives_or_panic(state_machine, &self.mainnet_wasms.archive_wasm); } From 82bd3a5e419ea42a06b30fc78b9e70c6cce8f662 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 20 Dec 2024 18:19:46 +0000 Subject: [PATCH 54/69] vary transfer amount in migration test --- rs/ledger_suite/tests/sm-tests/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 9cd11d9b96d..647bce8a363 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3112,7 +3112,7 @@ pub fn test_migration_resumes_from_frozen( for i in 2..2 + NUM_TRANSFERS { let to = Account::from(PrincipalId::new_user_test_id(i).0); - transfer(&env, canister_id, account, to, TRANSFER_AMOUNT) + transfer(&env, canister_id, account, to, TRANSFER_AMOUNT + i) .expect("failed to transfer funds"); } @@ -3134,7 +3134,7 @@ pub fn test_migration_resumes_from_frozen( canister_id, Account::from(PrincipalId::new_user_test_id(i).0), ); - assert_eq!(balance, Nat::from(TRANSFER_AMOUNT)); + assert_eq!(balance, Nat::from(TRANSFER_AMOUNT + i)); } }; From 5e64eeb69def66b275c451e295c04e41b9447f28 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Fri, 20 Dec 2024 18:25:21 +0000 Subject: [PATCH 55/69] vary transfer amount in migration test --- rs/ledger_suite/tests/sm-tests/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/ledger_suite/tests/sm-tests/src/lib.rs b/rs/ledger_suite/tests/sm-tests/src/lib.rs index 647bce8a363..c38b394251a 100644 --- a/rs/ledger_suite/tests/sm-tests/src/lib.rs +++ b/rs/ledger_suite/tests/sm-tests/src/lib.rs @@ -3008,7 +3008,7 @@ pub fn test_incomplete_migration_to_current( for i in 2..2 + NUM_TRANSFERS { let to = Account::from(PrincipalId::new_user_test_id(i).0); - transfer(&env, canister_id, account, to, TRANSFER_AMOUNT) + transfer(&env, canister_id, account, to, TRANSFER_AMOUNT + i) .expect("failed to transfer funds"); } @@ -3030,7 +3030,7 @@ pub fn test_incomplete_migration_to_current( canister_id, Account::from(PrincipalId::new_user_test_id(i).0), ); - assert_eq!(balance, Nat::from(TRANSFER_AMOUNT)); + assert_eq!(balance, Nat::from(TRANSFER_AMOUNT + i)); } }; From a0abf8205ccb163ee547ce0ab4f8a36c74fe8db6 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 30 Dec 2024 10:56:49 +0000 Subject: [PATCH 56/69] fix test name --- rs/ledger_suite/common/ledger_core/src/tokens/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs b/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs index 3379b49de9a..5d0324be9c8 100644 --- a/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs +++ b/rs/ledger_suite/common/ledger_core/src/tokens/tests.rs @@ -3,7 +3,7 @@ use ic_stable_structures::Storable; use proptest::prelude::{any, prop_assert_eq, proptest}; #[test] -fn timestamp_serialization() { +fn tokens_serialization() { proptest!(|(e8s in any::())| { let tokens = Tokens { e8s }; let new_tokens = Tokens::from_bytes(tokens.to_bytes()); From 45024a40034f3497e0b6eff77a52ebe6f2afc3ac Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 30 Dec 2024 12:54:03 +0000 Subject: [PATCH 57/69] fix tests --- rs/ledger_suite/icp/ledger/tests/tests.rs | 4 ++-- rs/ledger_suite/icp/tests/upgrade_downgrade.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 7cc8be6d809..05dbfd1ec80 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1262,7 +1262,7 @@ fn test_upgrade_serialization(ledger_wasm_mainnet: Vec) { upgrade_args, minter, false, - false, + true, ); } @@ -1292,7 +1292,7 @@ fn test_downgrade_from_incompatible_version() { ledger_wasm_next_version(), ledger_wasm(), encode_init_args, - true, + false, ); } diff --git a/rs/ledger_suite/icp/tests/upgrade_downgrade.rs b/rs/ledger_suite/icp/tests/upgrade_downgrade.rs index 9ea817b32d2..46ec2e24d3e 100644 --- a/rs/ledger_suite/icp/tests/upgrade_downgrade.rs +++ b/rs/ledger_suite/icp/tests/upgrade_downgrade.rs @@ -451,7 +451,7 @@ fn should_upgrade_and_downgrade_canister_suite() { setup.assert_index_ledger_parity(true); setup.upgrade_index_canister(UpgradeToVersion::MainNet); - setup.upgrade_ledger_canister(UpgradeToVersion::MainNet, true); + setup.upgrade_ledger_canister(UpgradeToVersion::MainNet, false); setup.upgrade_archive_canisters(UpgradeToVersion::MainNet); setup.assert_index_ledger_parity(true); From d8b4e054abb50b07d724e788e2fdcd57211ba483 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 7 Jan 2025 11:45:07 +0000 Subject: [PATCH 58/69] remove trimming --- .../common/ledger_canister_core/src/ledger.rs | 17 ----------------- rs/ledger_suite/icrc1/ledger/src/lib.rs | 18 +++++++----------- rs/ledger_suite/icrc1/ledger/src/main.rs | 6 +++--- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs index f347aa99a25..a97b5af638e 100644 --- a/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs +++ b/rs/ledger_suite/common/ledger_canister_core/src/ledger.rs @@ -197,29 +197,12 @@ pub enum TransferError { const APPROVE_PRUNE_LIMIT: usize = 100; /// Adds a new block with the specified transaction to the ledger. -/// Trim balances if necessary. pub fn apply_transaction( ledger: &mut L, transaction: L::Transaction, now: TimeStamp, effective_fee: L::Tokens, ) -> Result<(BlockIndex, HashOf), TransferError> -where - L: LedgerData, -{ - let result = apply_transaction_no_trimming(ledger, transaction, now, effective_fee); - trim_balances(ledger, now); - result -} - -/// Adds a new block with the specified transaction to the ledger. -/// Do not perform any balance trimming. -pub fn apply_transaction_no_trimming( - ledger: &mut L, - transaction: L::Transaction, - now: TimeStamp, - effective_fee: L::Tokens, -) -> Result<(BlockIndex, HashOf), TransferError> where L: LedgerData, { diff --git a/rs/ledger_suite/icrc1/ledger/src/lib.rs b/rs/ledger_suite/icrc1/ledger/src/lib.rs index 089942762e1..77dd0c654aa 100644 --- a/rs/ledger_suite/icrc1/ledger/src/lib.rs +++ b/rs/ledger_suite/icrc1/ledger/src/lib.rs @@ -22,9 +22,7 @@ use ic_ledger_canister_core::runtime::Runtime; use ic_ledger_canister_core::{ archive::ArchiveCanisterWasm, blockchain::Blockchain, - ledger::{ - apply_transaction_no_trimming, block_locations, LedgerContext, LedgerData, TransactionInfo, - }, + ledger::{apply_transaction, block_locations, LedgerContext, LedgerData, TransactionInfo}, range_utils, }; use ic_ledger_core::balances::BalancesStore; @@ -677,14 +675,12 @@ impl Ledger { ) }); let mint = Transaction::mint(account, amount, Some(now), None); - apply_transaction_no_trimming(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else( - |err| { - panic!( - "failed to mint {} tokens to {}: {:?}", - balance, account, err - ) - }, - ); + apply_transaction(&mut ledger, mint, now, Tokens::ZERO).unwrap_or_else(|err| { + panic!( + "failed to mint {} tokens to {}: {:?}", + balance, account, err + ) + }); } ledger diff --git a/rs/ledger_suite/icrc1/ledger/src/main.rs b/rs/ledger_suite/icrc1/ledger/src/main.rs index 18643abf59e..2014271b4a3 100644 --- a/rs/ledger_suite/icrc1/ledger/src/main.rs +++ b/rs/ledger_suite/icrc1/ledger/src/main.rs @@ -21,7 +21,7 @@ use ic_icrc1_ledger::{ }; use ic_icrc1_ledger::{InitArgs, Ledger, LedgerArgument, LedgerField, LedgerState}; use ic_ledger_canister_core::ledger::{ - apply_transaction_no_trimming, archive_blocks, LedgerAccess, LedgerContext, LedgerData, + apply_transaction, archive_blocks, LedgerAccess, LedgerContext, LedgerData, TransferError as CoreTransferError, }; use ic_ledger_canister_core::runtime::heap_memory_size_bytes; @@ -670,7 +670,7 @@ fn execute_transfer_not_async( ) }; - let (block_idx, _) = apply_transaction_no_trimming(ledger, tx, now, effective_fee)?; + let (block_idx, _) = apply_transaction(ledger, tx, now, effective_fee)?; Ok(block_idx) }) } @@ -869,7 +869,7 @@ async fn icrc2_approve(arg: ApproveArgs) -> Result { memo: arg.memo, }; - let (block_idx, _) = apply_transaction_no_trimming(ledger, tx, now, expected_fee_tokens) + let (block_idx, _) = apply_transaction(ledger, tx, now, expected_fee_tokens) .map_err(convert_transfer_error) .map_err(|err| { let err: ApproveError = match err.try_into() { From 223e17d7d81e0d0c6d40d79063e43adb183b4787 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 7 Jan 2025 11:53:51 +0000 Subject: [PATCH 59/69] reenable disabled tests --- rs/ledger_suite/icp/ledger/tests/tests.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index 05dbfd1ec80..e088014260a 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1266,7 +1266,6 @@ fn test_upgrade_serialization(ledger_wasm_mainnet: Vec) { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn test_multi_step_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration( @@ -1296,7 +1295,6 @@ fn test_downgrade_from_incompatible_version() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn test_stable_migration_endpoints_disabled_from_mainnet() { test_stable_migration_endpoints_disabled(ledger_wasm_mainnet()); @@ -1343,7 +1341,6 @@ fn test_stable_migration_endpoints_disabled(ledger_wasm_mainnet: Vec) { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn test_incomplete_migration_from_mainnet() { ic_ledger_suite_state_machine_tests::test_incomplete_migration( @@ -1353,7 +1350,6 @@ fn test_incomplete_migration_from_mainnet() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn test_incomplete_migration_from_v2() { ic_ledger_suite_state_machine_tests::test_incomplete_migration( @@ -1372,7 +1368,6 @@ fn test_incomplete_migration_to_current_from_mainnet() { ); } -#[ignore] // TODO: Re-enable as part of FI-1440 #[test] fn test_incomplete_migration_to_current_from_v2() { ic_ledger_suite_state_machine_tests::test_incomplete_migration_to_current( From e07aa5adcaf23ab5d08afb9e97342ba687b8b5fd Mon Sep 17 00:00:00 2001 From: maciejdfinity <122265298+maciejdfinity@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:44:53 +0100 Subject: [PATCH 60/69] Update rs/ledger_suite/icp/ledger/src/main.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mathias Björkqvist --- rs/ledger_suite/icp/ledger/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icp/ledger/src/main.rs b/rs/ledger_suite/icp/ledger/src/main.rs index 017163f2499..9964c6da9b2 100644 --- a/rs/ledger_suite/icp/ledger/src/main.rs +++ b/rs/ledger_suite/icp/ledger/src/main.rs @@ -833,7 +833,7 @@ fn post_upgrade(args: Option) { if upgrade_from_version < 2 { set_ledger_state(LedgerState::Migrating(LedgerField::Balances)); - print(format!("Upgrading from version {upgrade_from_version} which does store balances in stable structures, clearing stable balances data.").as_str()); + print(format!("Upgrading from version {upgrade_from_version} which does not store balances in stable structures, clearing stable balances data.").as_str()); clear_stable_balances_data(); ledger.copy_token_pool(); } From 624d94dded09fce094e7e38fe34e295411c32c46 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 8 Jan 2025 14:48:11 +0000 Subject: [PATCH 61/69] bump MAX_INSTRUCTIONS_PER_UPGRADE to 250B --- rs/ledger_suite/icp/ledger/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icp/ledger/src/main.rs b/rs/ledger_suite/icp/ledger/src/main.rs index 9964c6da9b2..ec70136b3cc 100644 --- a/rs/ledger_suite/icp/ledger/src/main.rs +++ b/rs/ledger_suite/icp/ledger/src/main.rs @@ -752,7 +752,7 @@ fn main() { const BUFFER_SIZE: usize = 8388608; #[cfg(not(feature = "low-upgrade-instruction-limits"))] -const MAX_INSTRUCTIONS_PER_UPGRADE: u64 = 190_000_000_000; +const MAX_INSTRUCTIONS_PER_UPGRADE: u64 = 250_000_000_000; #[cfg(not(feature = "low-upgrade-instruction-limits"))] const MAX_INSTRUCTIONS_PER_TIMER_CALL: u64 = 1_900_000_000; From da71ddaa5c35624ddbaff1ccd5e1a4d2116a329d Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Wed, 8 Jan 2025 16:14:42 +0000 Subject: [PATCH 62/69] fix golden nns tests --- rs/ledger_suite/icp/tests/golden_nns_state.rs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/rs/ledger_suite/icp/tests/golden_nns_state.rs b/rs/ledger_suite/icp/tests/golden_nns_state.rs index 74030fe52c3..8766ed034e9 100644 --- a/rs/ledger_suite/icp/tests/golden_nns_state.rs +++ b/rs/ledger_suite/icp/tests/golden_nns_state.rs @@ -22,7 +22,7 @@ use ic_nns_constants::{ LEDGER_CANISTER_INDEX_IN_NNS_SUBNET, LEDGER_INDEX_CANISTER_INDEX_IN_NNS_SUBNET, }; use ic_nns_test_utils_golden_nns_state::new_state_machine_with_golden_nns_state_or_panic; -use ic_state_machine_tests::{StateMachine, UserError}; +use ic_state_machine_tests::{ErrorCode, StateMachine, UserError}; use icp_ledger::{ AccountIdentifier, Archives, Block, FeatureFlags, LedgerCanisterPayload, UpgradeArgs, }; @@ -30,9 +30,8 @@ use std::time::Instant; /// The number of instructions that can be executed in a single canister upgrade. /// The limit () -/// is actually 300B, but in the ledger implementation we use a value slightly lower than the old -/// limit 200B. -const CANISTER_UPGRADE_INSTRUCTION_LIMIT: u64 = 190_000_000_000; +/// is actually 300B, but in the ledger implementation we use a slightly lower limit of 250B. +const CANISTER_UPGRADE_INSTRUCTION_LIMIT: u64 = 250_000_000_000; const INDEX_CANISTER_ID: CanisterId = CanisterId::from_u64(LEDGER_INDEX_CANISTER_INDEX_IN_NNS_SUBNET); const LEDGER_CANISTER_ID: CanisterId = CanisterId::from_u64(LEDGER_CANISTER_INDEX_IN_NNS_SUBNET); @@ -320,8 +319,21 @@ impl Setup { pub fn downgrade_to_mainnet(&self) { println!("Downgrading to mainnet version"); self.upgrade_index(&self.mainnet_wasms.index); - self.upgrade_ledger(&self.mainnet_wasms.ledger) - .expect("should successfully downgrade to the mainnet version"); + match self.upgrade_ledger(&self.mainnet_wasms.ledger) { + Ok(_) => { + panic!("should fail to downgrade ledger to mainnet version"); + } + Err(err) => { + // The ledger will still be running the master version, while the other canisters + // will be downgraded to the mainnet version. This is not an ideal situation, nor + // is it expected to happen in practice, but for the moment let's run the test to + // completion. + err.assert_contains( + ErrorCode::CanisterCalledTrap, + "Trying to downgrade from incompatible version", + ); + } + } self.check_ledger_metrics(ExpectMigration::No); self.upgrade_archive_canisters(&self.mainnet_wasms.archive); } From 1604074ddb37934daaf078867bd3d535b3403528 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 9 Jan 2025 16:28:11 +0000 Subject: [PATCH 63/69] cargo lock --- Cargo.lock | 101 ++--------------------------------------------------- 1 file changed, 2 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8515ac9b65..8a5851de88e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4417,11 +4417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-pki-types", ] @@ -5035,11 +5031,7 @@ dependencies = [ "clap 4.5.23", "hyper 1.5.2", "hyper-util", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-pemfile 2.2.0", "serde_json", "tokio", @@ -5168,13 +5160,8 @@ dependencies = [ "hyper 1.5.2", "hyper-util", "log", -<<<<<<< HEAD "rustls 0.23.18", - "rustls-native-certs 0.8.0", -======= - "rustls 0.23.20", "rustls-native-certs 0.8.1", ->>>>>>> master "rustls-pki-types", "tokio", "tokio-rustls 0.26.1", @@ -5637,11 +5624,7 @@ dependencies = [ "rand 0.8.5", "rcgen", "reqwest 0.12.9", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-acme", "rustls-pemfile 2.2.0", "rustls-platform-verifier", @@ -5734,11 +5717,7 @@ dependencies = [ "rcgen", "regex", "reqwest 0.12.9", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-pemfile 2.2.0", "serde", "serde_bytes", @@ -6070,11 +6049,7 @@ dependencies = [ "prost 0.13.4", "rand 0.8.5", "rand_chacha 0.3.1", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "serde", "serde_cbor", "tokio", @@ -6995,11 +6970,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rsa", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "serde", "sha2 0.10.8", "simple_asn1", @@ -7760,11 +7731,7 @@ dependencies = [ "ic-types-test-utils", "rand 0.8.5", "rand_chacha 0.3.1", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "tempfile", "tokio", ] @@ -7964,11 +7931,7 @@ dependencies = [ "ic-types", "pkcs8", "rand 0.8.5", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "signature", "time", "tokio", @@ -8004,11 +7967,7 @@ dependencies = [ "ic-types", "json5", "maplit", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "serde", "thiserror 2.0.8", "x509-parser", @@ -8021,11 +7980,7 @@ dependencies = [ "ic-base-types", "ic-crypto-tls-interfaces", "mockall", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master ] [[package]] @@ -8561,11 +8516,7 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.9", "rstest", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "serde", "serde_bytes", "serde_cbor", @@ -8686,11 +8637,7 @@ dependencies = [ "prometheus", "rand 0.8.5", "rstest", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-pemfile 2.2.0", "serde", "serde_json", @@ -10755,11 +10702,7 @@ dependencies = [ "quinn", "quinn-udp", "rcgen", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "serde", "slog", "tempfile", @@ -10923,11 +10866,7 @@ dependencies = [ "prost 0.13.4", "quinn", "rstest", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "slog", "socket2 0.5.8", "static_assertions", @@ -14776,11 +14715,7 @@ dependencies = [ "k8s-openapi", "kube-core", "pem 3.0.4", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-pemfile 2.2.0", "secrecy", "serde", @@ -17902,17 +17837,10 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", -<<<<<<< HEAD - "rustc-hash 2.0.0", - "rustls 0.23.18", - "socket2 0.5.7", - "thiserror 1.0.68", -======= "rustc-hash 2.1.0", - "rustls 0.23.20", + "rustls 0.23.18", "socket2 0.5.8", "thiserror 2.0.8", ->>>>>>> master "tokio", "tracing", ] @@ -17927,14 +17855,9 @@ dependencies = [ "getrandom", "rand 0.8.5", "ring 0.17.8", -<<<<<<< HEAD - "rustc-hash 2.0.0", - "rustls 0.23.18", -======= "rustc-hash 2.1.0", - "rustls 0.23.20", + "rustls 0.23.18", "rustls-pki-types", ->>>>>>> master "slab", "thiserror 2.0.8", "tinyvec", @@ -18584,13 +18507,8 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", -<<<<<<< HEAD "rustls 0.23.18", - "rustls-native-certs 0.8.0", -======= - "rustls 0.23.20", "rustls-native-certs 0.8.1", ->>>>>>> master "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", @@ -19075,15 +18993,9 @@ dependencies = [ [[package]] name = "rustls" -<<<<<<< HEAD version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" -======= -version = "0.23.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" ->>>>>>> master dependencies = [ "brotli 7.0.0", "brotli-decompressor", @@ -19185,11 +19097,7 @@ dependencies = [ "jni", "log", "once_cell", -<<<<<<< HEAD "rustls 0.23.18", -======= - "rustls 0.23.20", ->>>>>>> master "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", @@ -21122,12 +21030,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ -<<<<<<< HEAD "rustls 0.23.18", - "rustls-pki-types", -======= - "rustls 0.23.20", ->>>>>>> master "tokio", ] From 5c7a01f6eab84d08bdc6ef8023aec06827df9377 Mon Sep 17 00:00:00 2001 From: maciejdfinity <122265298+maciejdfinity@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:16:28 +0100 Subject: [PATCH 64/69] Update rs/ledger_suite/icp/ledger/tests/tests.rs Co-authored-by: mraszyk <31483726+mraszyk@users.noreply.github.com> --- rs/ledger_suite/icp/ledger/tests/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ledger_suite/icp/ledger/tests/tests.rs b/rs/ledger_suite/icp/ledger/tests/tests.rs index e088014260a..5880d38248d 100644 --- a/rs/ledger_suite/icp/ledger/tests/tests.rs +++ b/rs/ledger_suite/icp/ledger/tests/tests.rs @@ -1231,7 +1231,7 @@ fn test_block_transformation() { } #[test] -fn test_upgrade_serialization_from_master() { +fn test_upgrade_serialization_from_mainnet() { test_upgrade_serialization(ledger_wasm_mainnet()); } From e777205ccd2e66233755f8e79ab661ac4e62ce27 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Thu, 23 Jan 2025 14:36:51 +0000 Subject: [PATCH 65/69] increase limit to 300B, log the post_upgrade limit --- rs/ledger_suite/icp/ledger/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/ledger_suite/icp/ledger/src/main.rs b/rs/ledger_suite/icp/ledger/src/main.rs index ec70136b3cc..7c2b2720913 100644 --- a/rs/ledger_suite/icp/ledger/src/main.rs +++ b/rs/ledger_suite/icp/ledger/src/main.rs @@ -752,7 +752,7 @@ fn main() { const BUFFER_SIZE: usize = 8388608; #[cfg(not(feature = "low-upgrade-instruction-limits"))] -const MAX_INSTRUCTIONS_PER_UPGRADE: u64 = 250_000_000_000; +const MAX_INSTRUCTIONS_PER_UPGRADE: u64 = 300_000_000_000; #[cfg(not(feature = "low-upgrade-instruction-limits"))] const MAX_INSTRUCTIONS_PER_TIMER_CALL: u64 = 1_900_000_000; @@ -897,7 +897,7 @@ fn migrate_next_part(instruction_limit: u64) { } } let instructions_migration = instruction_counter() - instructions_migration_start; - let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations} balances: {migrated_balances}. Migration step instructions: {instructions_migration}, total instructions used in message: {}." , + let msg = format!("Number of elements migrated: allowances: {migrated_allowances} expirations: {migrated_expirations} balances: {migrated_balances}. Migration step instructions: {instructions_migration}, total instructions used in message: {}, limit: {instruction_limit}." , instruction_counter()); if !is_ready() { print(format!( From 0a58cfafc4c6e22b0fcb4df741508a56587a713d Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Mon, 27 Jan 2025 15:26:04 +0000 Subject: [PATCH 66/69] bump icp ledger wasm size limit --- publish/canisters/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/publish/canisters/BUILD.bazel b/publish/canisters/BUILD.bazel index ff10d83047a..289eeb1c3a7 100644 --- a/publish/canisters/BUILD.bazel +++ b/publish/canisters/BUILD.bazel @@ -66,7 +66,7 @@ CANISTERS_MAX_SIZE_COMPRESSED_E5_BYTES = { # Size when constraint addded: 841_234 bytes "ledger-canister.wasm.gz": "9", # Size when constraint addded: 847_186 bytes - "ledger-canister_notify-method.wasm.gz": "9", + "ledger-canister_notify-method.wasm.gz": "10", # -- XC team -- # Size when constraint addded: 447_593 bytes From 45e16c6e57e94e578b0739f9160c63474952229f Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 28 Jan 2025 08:17:02 +0000 Subject: [PATCH 67/69] delete nns inspector tool --- Cargo.lock | 19 -- Cargo.toml | 1 - rs/nns/inspector/BUILD.bazel | 30 -- rs/nns/inspector/Cargo.toml | 20 -- rs/nns/inspector/README.md | 58 ---- .../screenshot-canister-state-path.png | Bin 396356 -> 0 bytes rs/nns/inspector/src/main.rs | 273 ------------------ 7 files changed, 401 deletions(-) delete mode 100644 rs/nns/inspector/BUILD.bazel delete mode 100644 rs/nns/inspector/Cargo.toml delete mode 100644 rs/nns/inspector/README.md delete mode 100644 rs/nns/inspector/screenshot-canister-state-path.png delete mode 100644 rs/nns/inspector/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 753146b4f9c..e67b45349ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10557,25 +10557,6 @@ dependencies = [ "url", ] -[[package]] -name = "ic-nns-inspector" -version = "0.1.0" -dependencies = [ - "clap 4.5.27", - "csv", - "hex", - "ic-base-types", - "ic-nns-constants", - "ic-nns-governance-api", - "ic-nns-gtc", - "icp-ledger", - "ledger-canister", - "prost 0.13.4", - "serde", - "serde_cbor", - "stable_reader", -] - [[package]] name = "ic-nns-integration-tests" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index a18910e51ab..b71047a052f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -216,7 +216,6 @@ members = [ "rs/nns/handlers/root/interface", "rs/nns/identity", "rs/nns/init", - "rs/nns/inspector", "rs/nns/integration_tests", "rs/nns/nns-ui", "rs/nns/test_utils", diff --git a/rs/nns/inspector/BUILD.bazel b/rs/nns/inspector/BUILD.bazel deleted file mode 100644 index 0ad7574ed85..00000000000 --- a/rs/nns/inspector/BUILD.bazel +++ /dev/null @@ -1,30 +0,0 @@ -load("@rules_rust//rust:defs.bzl", "rust_binary") - -package(default_visibility = ["//visibility:public"]) - -DEPENDENCIES = [ - # Keep sorted. - "//rs/ledger_suite/icp:icp_ledger", - "//rs/ledger_suite/icp/ledger", - "//rs/nns/constants", - "//rs/nns/governance/api", - "//rs/nns/gtc", - "//rs/rust_canisters/stable_reader", - "//rs/types/base_types", - "@crate_index//:clap", - "@crate_index//:csv", - "@crate_index//:hex", - "@crate_index//:prost", - "@crate_index//:serde", - "@crate_index//:serde_cbor", -] - -rust_binary( - name = "inspector", - srcs = glob(["src/**/*.rs"]), - aliases = {}, - crate_name = "ic_nns_inspector", - proc_macro_deps = [], - version = "0.1.0", - deps = DEPENDENCIES, -) diff --git a/rs/nns/inspector/Cargo.toml b/rs/nns/inspector/Cargo.toml deleted file mode 100644 index 8d38ba9a6d9..00000000000 --- a/rs/nns/inspector/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "ic-nns-inspector" -version = "0.1.0" -edition = "2021" - - -[dependencies] -clap = { workspace = true } -csv = "1.1" -hex = { workspace = true } -ic-base-types = { path = "../../types/base_types" } -ic-nns-constants = { path = "../constants" } -ic-nns-governance-api = { path = "../governance/api" } -ic-nns-gtc = { path = "../gtc" } -icp-ledger = { path = "../../ledger_suite/icp" } -ledger-canister = { path = "../../ledger_suite/icp/ledger" } -prost = { workspace = true } -serde = { workspace = true } -serde_cbor = { workspace = true } -stable_reader = { path = "../../rust_canisters/stable_reader" } diff --git a/rs/nns/inspector/README.md b/rs/nns/inspector/README.md deleted file mode 100644 index 029a65fbd62..00000000000 --- a/rs/nns/inspector/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# How to audit the state of NNS canisters - -This directory contains a tool aimed at auditing the state of NNS canisters immediately after bootstrap. - -## Upgrade NNS canisters - -To force NNS canisters to write stable memory, they need to be upgraded. -See `launch/upgrade_nns_canister.sh`. - -## Fetch canister states - -Use the replica dashboard on an NNS replica to locate the canister state root path. -Click the arrow to expand the debug info for any NNS canister and search for `canister_root`. -Fetch the directory called `tip/canister_states` to a location reachable from the tool -- e.g., using `rsync` if this is on a remote replica. -See the following screenshot as an example: - -![Screenshot](screenshot-canister-state-path.png?raw=true "Screenshot") - - -## Decode stable memories - -Run: -`cargo run --bin ic-nns-inspector -- ` - -This will create various files in the desired output directory that can be audited. - -## Diff with the initial state - -The most important part of the audit is to verify that the governance proto corresponds matches the desired initial state. -"Matches" here does not mean "is equal to" --- in particular, more proposals and recent ballots will appear in the stable memory than in the initial state. -Therefore "matches" should be understood as "differs in expected ways". - -Here is an example command line for that. -Assuming that desired initial state is `../testnet/env/bootstrap/initial-governance.pb` and that the output directory is `~/stable`, one can run: - -``` -protoc \ - -I nns/governance/proto \ - -I nns/common/proto \ - -I types/base_types/proto \ - -I ledger_suite/icp/proto \ - nns/governance/proto/ic_nns_governance/pb/v1/governance.proto \ - --decode ic_nns_governance.pb.v1.Governance \ - < ../testnet/env/bootstrap/initial-governance.pb \ - > ~/stable/initial-governance-frompb.textproto -``` - -then: -``` -meld ~/stable/governance_stable_memory.textproto ~/stable/initial-governance-frompb.textproto -``` - -`meld` is a graphical diff viewer. -Others can be used, according to preference. - -In case the `initial-governance.pb` was generated from `.textproto`, it is tempting to skip the first step and simply compare `governance_stable_memory.textproto` with that. -Alas, this leads to poor result, as the textproto representation is not unique (e.g., there are several ways to escape in bytes arrays). -Regenerating the textproto from the pb will minimize spurious diffs. diff --git a/rs/nns/inspector/screenshot-canister-state-path.png b/rs/nns/inspector/screenshot-canister-state-path.png deleted file mode 100644 index d441e9d57b233c34ce7ef6a4157e33e1892e50fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 396356 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 RBEotxClw~06e8o%5sn3a{gC^HHzz( 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ü?g|40+!|>T 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 diff --git a/rs/nns/inspector/src/main.rs b/rs/nns/inspector/src/main.rs deleted file mode 100644 index ee12e062c8d..00000000000 --- a/rs/nns/inspector/src/main.rs +++ /dev/null @@ -1,273 +0,0 @@ -//! An utility to help inspecting the stable memory of NNS canisters. - -use clap::Parser; -use ic_base_types::CanisterId; -use ic_nns_constants::{ - CYCLES_MINTING_CANISTER_ID, GENESIS_TOKEN_CANISTER_ID, GOVERNANCE_CANISTER_ID, - REGISTRY_CANISTER_ID, -}; -use ic_nns_governance_api::pb::v1::{Governance as GovernanceProto, Neuron}; -use ic_nns_gtc::pb::v1::Gtc as GtcProto; -use icp_ledger::{AccountIdentifier, Subaccount}; -use prost::Message; -use std::{ - convert::TryInto, - fs::File, - io::Read, - path::{Path, PathBuf}, - string::ToString, -}; - -/// Command line argument to the utility. -#[derive(Debug, Parser)] -#[clap( - name = "nns-inspector", - about = "Read and decode the NNS's stable memory.", - version -)] -struct CliArgs { - /// Path to stable the `canister_states` directory - input: PathBuf, - - #[clap(default_value = ".")] - output: PathBuf, - - /// The location of the "rs" directory. Used to find .proto files. - #[clap(long, default_value = ".")] - rs: PathBuf, -} - -/// Main method to run the utility. -fn main() { - let args = CliArgs::try_parse_from(std::env::args()) - .unwrap_or_else(|e| panic!("Illegal arguments: {}", e)); - - assert!( - args.input.is_dir(), - "{} is not a directory", - args.input.display() - ); - match std::fs::create_dir(args.output.clone()) { - Ok(()) => eprintln!("Created output dir {}", args.output.display()), - Err(_) => eprintln!( - "Could not create output dir {}. It may mean it already exists, so continuing. \ - This may override existing files.", - args.output.display() - ), - } - - // Registry. - // Stable memory = binary proto, type RegistryCanisterStableStorage. - match extract_stable_memory(&args, REGISTRY_CANISTER_ID, "registry_stable_memory.pb") { - Ok(pb) => eprintln!("Extracted registry stable memory to {}", pb.display()), - Err(e) => eprintln!("Could not extract the registry stable memory: {}", e), - } - - // Governance. - // Stable memory = binary proto, type Governance. - match extract_stable_memory(&args, GOVERNANCE_CANISTER_ID, "governance_stable_memory.pb") { - Ok(pb) => decode_governance_stable_memory(pb, &args.output, &args.rs), - Err(e) => eprintln!("Could not extract the governance stable memory: {}", e), - } - - // Gtc. - // Stable memory = binary proto, type Gtc. - match extract_stable_memory(&args, GENESIS_TOKEN_CANISTER_ID, "gtc_stable_memory.pb") { - Ok(pb) => decode_gtc_stable_memory(pb, &args.output, &args.rs), - Err(e) => eprintln!("Could not extract the gtc stable memory: {}", e), - } - - // Cycle minting. - // Stable memory = binary candid, type State. - match extract_stable_memory( - &args, - CYCLES_MINTING_CANISTER_ID, - "cycles_stable_memory.didb", - ) { - Ok(_) => eprintln!("Wrote cycles_stable_memory.didb"), - Err(e) => eprintln!("Could not extract the cycles stable memory: {}", e), - } -} - -/// Extract a stable_memory.bin file. -/// -/// This depends only on the stable memory using the `dfn_core::stable` library, -/// not on the actual data schema inside. -/// -/// Returns the PathBuf to the extracted stable memory. -fn extract_stable_memory( - args: &CliArgs, - id: CanisterId, - filename: &str, -) -> std::io::Result { - let encoded = args - .input - .join(hex::encode(id.get_ref().as_slice())) - .join("stable_memory.bin"); - assert!(encoded.is_file(), "{} is not a file.", encoded.display()); - let decoded = args.output.join(filename); - stable_reader::read(&mut File::open(encoded)?, File::create(decoded.clone())?)?; - Ok(decoded) -} - -/// Extract of a neuron data suitable for csv output. -#[derive(serde::Serialize)] -struct NeuronRecord { - id: String, - account_hex: String, - controller: String, - hot_keys: String, - cached_neuron_stake_e8s: u64, - neuron_fees_e8s: u64, - aging_since_timestamp_seconds: u64, - kyc_verified: bool, - maturity_e8s_equivalent: u64, - not_for_profit: bool, - account_id: String, -} - -/// Decode stable memory for the governance canister. -/// -/// gov_pb is expected to be a binary Governance proto. Extraction should have -/// already happened. -fn decode_governance_stable_memory(gov_pb: PathBuf, output: &Path, rs: &Path) { - // Decode - // It's REALLY IMPORTANT to use `protoc` here, NOT the prost library. - // The prost generated code silently drops all unknown fields when reading - // serialized protobuf, hence it is NOT suitable for state auditing, or in - // general for debugging. - let mut cmd_base = std::process::Command::new("protoc"); - let cmd = cmd_base - // -I: where to find included protos (transitively) - .args(["-I", "nns/governance/proto"]) - .args(["-I", "ledger_suite/icp/proto"]) - .args(["-I", "types/base_types/proto"]) - .args(["-I", "nns/common/proto"]) - // Main arg: the main proto file - .arg("nns/governance/proto/ic_nns_governance/pb/v1/governance.proto") - // the actual command - .args(["--decode", "ic_nns_governance.pb.v1.Governance"]) - .current_dir(rs) - .stdin(File::open(gov_pb.clone()).unwrap()) - .stdout(File::create(output.join("governance_stable_memory.textproto")).unwrap()); - let status = cmd.status().unwrap(); - match status.success() { - true => eprintln!("Wrote governance_stable_memory.textproto"), - false => eprintln!( - "Something went wrong with parsing the governance proto. The command was: {:?}", - cmd - ), - }; - - // This time we use prost. This is fine: this is for an EXTRACT of the data. - let mut bytes = Vec::::new(); - File::open(gov_pb).unwrap().read_to_end(&mut bytes).unwrap(); - match GovernanceProto::decode(bytes.as_slice()) { - Err(e) => eprintln!("Can't prost-deserialize the governance proto: {}", e), - Ok(proto) => { - let mut csv_writer = - csv::Writer::from_path(output.join("governance_neurons_EXTRACT.csv")).unwrap(); - let mut neurons: Vec = proto.neurons.values().cloned().collect(); - neurons.sort_by_key(|n| n.id.as_ref().map_or(0, |nid| nid.id)); - for n in neurons { - let record = NeuronRecord { - id: n - .id - .map_or_else(|| "none".to_string(), |nid| nid.id.to_string()), - account_hex: hex::encode(n.account.as_slice()), - controller: n - .controller - .map_or_else(|| "none".to_string(), |c| c.to_string()), - hot_keys: n - .hot_keys - .iter() - .map(ToString::to_string) - .collect::>() - .join(";"), - cached_neuron_stake_e8s: n.cached_neuron_stake_e8s, - neuron_fees_e8s: n.neuron_fees_e8s, - aging_since_timestamp_seconds: n.aging_since_timestamp_seconds, - kyc_verified: n.kyc_verified, - maturity_e8s_equivalent: n.maturity_e8s_equivalent, - not_for_profit: n.not_for_profit, - account_id: AccountIdentifier::new( - GOVERNANCE_CANISTER_ID.get(), - Some(Subaccount(n.account.as_slice().try_into().unwrap())), - ) - .to_string(), - }; - csv_writer.serialize(record).unwrap(); - } - eprintln!("Wrote governance_neurons_EXTRACT.csv"); - } - } -} - -/// The type of record expected to be found in the GTC canister's stable memory. -#[derive(serde::Serialize)] -struct GtcAccountRecord { - account_address: String, - neuron_ids: String, - account_value_icpts: u32, - has_claimed: bool, - has_donated: bool, -} - -/// Decode stable memory for the GTC canister. -fn decode_gtc_stable_memory(gtc_pb: PathBuf, output: &Path, rs: &Path) { - let mut cmd_base = std::process::Command::new("protoc"); - let cmd = cmd_base - // -I: where to find included protos (transitively) - .args(["-I", "nns/governance/proto"]) - .args(["-I", "ledger_suite/icp/proto"]) - .args(["-I", "types/base_types/proto"]) - .args(["-I", "nns/common/proto"]) - .args(["-I", "nns/gtc/proto"]) - // Main arg: the main proto file - .arg("nns/gtc/proto/ic_nns_gtc/pb/v1/gtc.proto") - // the actual command - .args(["--decode", "ic_nns_gtc.pb.v1.Gtc"]) - .current_dir(rs) - .stdin(File::open(gtc_pb.clone()).unwrap()) - .stdout(File::create(output.join("gtc_stable_memory.textproto")).unwrap()); - let status = cmd.status().unwrap(); - match status.success() { - true => eprintln!("Wrote gtc_stable_memory.textproto"), - false => eprintln!( - "Something went wrong with parsing the gtc proto. The command was: {:?}", - cmd - ), - } - - let mut bytes = Vec::::new(); - File::open(gtc_pb).unwrap().read_to_end(&mut bytes).unwrap(); - let proto = match GtcProto::decode(bytes.as_slice()) { - Err(e) => { - eprintln!("Can't prost-deserialize the gtc proto: {}", e); - return; - } - Ok(p) => p, - }; - let mut csv_writer = csv::Writer::from_path(output.join("gtc_accounts_EXTRACT.csv")).unwrap(); - let mut records: Vec = proto - .accounts - .iter() - .map(|(addr, s)| GtcAccountRecord { - account_address: addr.to_string(), - neuron_ids: s - .neuron_ids - .iter() - .map(|id| id.id.to_string()) - .collect::>() - .join(";"), - account_value_icpts: s.icpts, - has_claimed: s.has_claimed, - has_donated: s.has_donated, - }) - .collect(); - records.sort_by_key(|record| record.account_address.clone()); - for r in records { - csv_writer.serialize(r).unwrap(); - } - eprintln!("Wrote gtc_accounts_EXTRACT.csv"); -} From f0f1d99b3f0b9cf766215e020617ad9b60d3e258 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 28 Jan 2025 09:56:39 +0000 Subject: [PATCH 68/69] update size in comment --- publish/canisters/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/publish/canisters/BUILD.bazel b/publish/canisters/BUILD.bazel index 289eeb1c3a7..e353b17af02 100644 --- a/publish/canisters/BUILD.bazel +++ b/publish/canisters/BUILD.bazel @@ -65,7 +65,7 @@ CANISTERS_MAX_SIZE_COMPRESSED_E5_BYTES = { "ic-icrc1-ledger-u256.wasm.gz": "7", # Size when constraint addded: 841_234 bytes "ledger-canister.wasm.gz": "9", - # Size when constraint addded: 847_186 bytes + # Size when constraint addded: 906_940 bytes "ledger-canister_notify-method.wasm.gz": "10", # -- XC team -- From bef1a7b25d8b4c84fee3e64ae5f43140dffef908 Mon Sep 17 00:00:00 2001 From: Maciej Modelski Date: Tue, 28 Jan 2025 10:48:15 +0000 Subject: [PATCH 69/69] update golden state test instruction limit --- rs/ledger_suite/icp/tests/golden_nns_state.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rs/ledger_suite/icp/tests/golden_nns_state.rs b/rs/ledger_suite/icp/tests/golden_nns_state.rs index 8766ed034e9..5249d99834e 100644 --- a/rs/ledger_suite/icp/tests/golden_nns_state.rs +++ b/rs/ledger_suite/icp/tests/golden_nns_state.rs @@ -28,10 +28,9 @@ use icp_ledger::{ }; use std::time::Instant; -/// The number of instructions that can be executed in a single canister upgrade. -/// The limit () -/// is actually 300B, but in the ledger implementation we use a slightly lower limit of 250B. -const CANISTER_UPGRADE_INSTRUCTION_LIMIT: u64 = 250_000_000_000; +/// The number of instructions that can be executed in a single canister upgrade as per +/// https://internetcomputer.org/docs/current/developer-docs/smart-contracts/maintain/resource-limits#resource-constraints-and-limits +const CANISTER_UPGRADE_INSTRUCTION_LIMIT: u64 = 300_000_000_000; const INDEX_CANISTER_ID: CanisterId = CanisterId::from_u64(LEDGER_INDEX_CANISTER_INDEX_IN_NNS_SUBNET); const LEDGER_CANISTER_ID: CanisterId = CanisterId::from_u64(LEDGER_CANISTER_INDEX_IN_NNS_SUBNET);