Skip to content

Commit

Permalink
Add test reproducing the BIL ledger upgrade and fix flow
Browse files Browse the repository at this point in the history
  • Loading branch information
mbjorkqvist committed Jan 18, 2025
1 parent 3cd9fd5 commit 58c4dd1
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 2 deletions.
6 changes: 6 additions & 0 deletions WORKSPACE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ canisters(
"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_ledger_v4": "ic-icrc1-ledger.wasm.gz",
"ck_btc_ledger_bil": "ic-icrc1-ledger.wasm.gz",
"ck_btc_ledger_bil_install": "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",
Expand Down Expand Up @@ -58,6 +61,9 @@ canisters(
"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_ledger_v4": "mainnet_ckbtc_ic-icrc1-ledger-v4",
"ck_btc_ledger_bil": "mainnet_ckbtc_ic-icrc1-ledger-bil",
"ck_btc_ledger_bil_install": "mainnet_ckbtc_ic-icrc1-ledger-bil-install",
"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",
Expand Down
14 changes: 13 additions & 1 deletion mainnet-canister-revisions.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@
"rev": "e54d3fa34ded227c885d04e64505fa4b5d564743",
"sha256": "3d808fa63a3d8ebd4510c0400aa078e99a31afaa0515f0b68778f929ce4b2a46"
},
"ck_btc_ledger_v4": {
"rev": "c741e349451edf0c9792149ad439bb32a0161371",
"sha256": "3b03d1bb1145edbcd11101ab2788517bc0f427c3bd7b342b9e3e7f42e29d5822"
},
"ck_btc_ledger_bil": {
"rev": "af791155fd0ccfcba65bfe21d976e69e923078bf",
"sha256": "f715516b1688a4de55d297c6bf770c0843f2fcd8ead81c4ace08d13886002a8d"
},
"ck_btc_ledger_bil_install": {
"rev": "aba60ffbc46acfc8990bf4d5685c1360bd7026b9",
"sha256": "67cfcbabb79e683b6fc855450d9972c9efaa7a1cd28c6387965616fbead191ea"
},
"ck_eth_archive": {
"rev": "2190613d3b5bcd9b74c382b22d151580b8ac271a",
"sha256": "2d25f7831894100d48aa9043c65e87c293487523f0958c15760027d004fbbda9"
Expand Down Expand Up @@ -107,4 +119,4 @@
"rev": "aa91ecacdf3824e193e21b70e0127e8d3edab51a",
"sha256": "8313ac22d2ef0a0c1290a85b47f235cfa24ca2c96d095b8dbed5502483b9cd18"
}
}
}
6 changes: 6 additions & 0 deletions rs/ledger_suite/icrc1/ledger/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ rust_test(
"//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-v4//file",
"@mainnet_ckbtc_ic-icrc1-ledger-bil//file",
"@mainnet_ckbtc_ic-icrc1-ledger-bil-install//file",
"@mainnet_ckbtc_ic-icrc1-ledger//file",
"@mainnet_cketh_ic-icrc1-ledger-u256-v1//file",
"@mainnet_cketh_ic-icrc1-ledger-u256-v2//file",
Expand All @@ -291,6 +294,9 @@ rust_test(
"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)",
"CKBTC_IC_ICRC1_LEDGER_V4_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-v4//file)",
"CKBTC_IC_ICRC1_LEDGER_BIL_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-bil//file)",
"CKBTC_IC_ICRC1_LEDGER_BIL_INSTALL_VERSION_WASM_PATH": "$(rootpath @mainnet_ckbtc_ic-icrc1-ledger-bil-install//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)",
Expand Down
63 changes: 63 additions & 0 deletions rs/ledger_suite/icrc1/ledger/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ fn ledger_mainnet_v2_wasm() -> Vec<u8> {
mainnet_wasm
}

#[cfg(not(feature = "u256-tokens"))]
fn ledger_mainnet_bil_wasm() -> Vec<u8> {
let mainnet_wasm = ledger_mainnet_bil_u64_wasm();
mainnet_wasm
}

#[cfg(not(feature = "u256-tokens"))]
fn ledger_mainnet_bil_install_wasm() -> Vec<u8> {
let mainnet_wasm = ledger_mainnet_bil_install_u64_wasm();
mainnet_wasm
}

fn ledger_mainnet_v1_wasm() -> Vec<u8> {
#[cfg(not(feature = "u256-tokens"))]
let mainnet_wasm = ledger_mainnet_v1_u64_wasm();
Expand All @@ -103,11 +115,27 @@ fn ledger_mainnet_v2_u64_wasm() -> Vec<u8> {
std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V2_VERSION_WASM_PATH").unwrap()).unwrap()
}

#[cfg(not(feature = "u256-tokens"))]
fn ledger_mainnet_bil_u64_wasm() -> Vec<u8> {
std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_BIL_VERSION_WASM_PATH").unwrap()).unwrap()
}

#[cfg(not(feature = "u256-tokens"))]
fn ledger_mainnet_bil_install_u64_wasm() -> Vec<u8> {
std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_BIL_INSTALL_VERSION_WASM_PATH").unwrap())
.unwrap()
}

#[cfg(not(feature = "u256-tokens"))]
fn ledger_mainnet_v1_u64_wasm() -> Vec<u8> {
std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V1_VERSION_WASM_PATH").unwrap()).unwrap()
}

#[cfg(not(feature = "u256-tokens"))]
fn ledger_mainnet_v4_u64_wasm() -> Vec<u8> {
std::fs::read(std::env::var("CKBTC_IC_ICRC1_LEDGER_V4_VERSION_WASM_PATH").unwrap()).unwrap()
}

fn ledger_mainnet_u256_wasm() -> Vec<u8> {
std::fs::read(std::env::var("CKETH_IC_ICRC1_LEDGER_DEPLOYED_VERSION_WASM_PATH").unwrap())
.unwrap()
Expand Down Expand Up @@ -481,6 +509,17 @@ fn icrc1_test_upgrade_serialization_from_v2() {
icrc1_test_upgrade_serialization(ledger_mainnet_v2_wasm());
}

#[cfg(not(feature = "u256-tokens"))]
#[test]
fn icrc1_test_upgrade_serialization_from_bil() {
icrc1_test_upgrade_serialization_bil(
ledger_mainnet_bil_install_wasm(),
ledger_mainnet_bil_wasm(),
ledger_wasm(),
ledger_mainnet_v4_u64_wasm(),
);
}

fn icrc1_test_upgrade_serialization(ledger_mainnet_wasm: Vec<u8>) {
let minter = Arc::new(minter_identity());
let builder = LedgerInitArgsBuilder::with_symbol_and_name(TOKEN_SYMBOL, TOKEN_NAME)
Expand All @@ -499,6 +538,30 @@ fn icrc1_test_upgrade_serialization(ledger_mainnet_wasm: Vec<u8>) {
);
}

fn icrc1_test_upgrade_serialization_bil(
ledger_install_wasm: Vec<u8>,
ledger_upgrade_wasm: Vec<u8>,
ledger_fix_wasm: Vec<u8>,
ledger_v4_wasm: Vec<u8>,
) {
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_bil_migration_fix::<Tokens>(
ledger_install_wasm,
ledger_upgrade_wasm,
ledger_fix_wasm,
ledger_v4_wasm,
init_args,
upgrade_args,
minter,
true,
);
}

#[test]
fn icrc1_test_multi_step_migration_from_mainnet() {
ic_ledger_suite_state_machine_tests::icrc1_test_multi_step_migration(
Expand Down
144 changes: 143 additions & 1 deletion rs/ledger_suite/tests/sm-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::in_memory_ledger::{verify_ledger_state, InMemoryLedger};
use crate::in_memory_ledger::{verify_ledger_state, InMemoryLedger, InMemoryLedgerState};
use crate::metrics::{parse_metric, retrieve_metrics};
use assert_matches::assert_matches;
use candid::{CandidType, Decode, Encode, Int, Nat, Principal};
Expand Down Expand Up @@ -2406,6 +2406,148 @@ fn apply_arg_with_caller(
}
}

pub fn test_bil_migration_fix<Tokens>(
ledger_wasm_install: Vec<u8>,
ledger_wasm_upgrade: Vec<u8>,
ledger_wasm_fix: Vec<u8>,
ledger_wasm_v4: Vec<u8>,
init_args: Vec<u8>,
upgrade_args: Vec<u8>,
minter: Arc<BasicIdentity>,
verify_blocks: bool,
) where
Tokens: TokensType + Default + std::fmt::Display + From<u64>,
{
let mut runner = TestRunner::new(TestRunnerConfig::with_cases(1));
let now = SystemTime::now();
let minter_principal: Principal = minter.sender().unwrap();
const INITIAL_TX_BATCH_SIZE: usize = 100;
const ADDITIONAL_TX_BATCH_SIZE: usize = 15;
const TOTAL_TX_COUNT: usize = INITIAL_TX_BATCH_SIZE + 9 * ADDITIONAL_TX_BATCH_SIZE;
runner
.run(
&(valid_transactions_strategy(minter, FEE, TOTAL_TX_COUNT, now).no_shrink(),),
|(transactions,)| {
let env = StateMachine::new();
env.set_time(now);
let ledger_id = env
.install_canister(ledger_wasm_install.clone(), init_args.clone(), None)
.unwrap();

let mut in_memory_ledger = InMemoryLedger::<Account, Tokens>::default();

let mut tx_index = 0;
let mut tx_index_target = INITIAL_TX_BATCH_SIZE;

let mut add_tx_and_verify = |in_memory_ledger: &mut InMemoryLedger::<Account, Tokens>, num_mints: u64| {
while tx_index < tx_index_target {
apply_arg_with_caller(&env, ledger_id, &transactions[tx_index]);
in_memory_ledger.apply_arg_with_caller(
&transactions[tx_index],
TimeStamp::from_nanos_since_unix_epoch(system_time_to_nanos(
env.time(),
)),
minter_principal,
Some(FEE.into()),
);
tx_index += 1;
}
tx_index_target += ADDITIONAL_TX_BATCH_SIZE;
in_memory_ledger.verify_balances_and_allowances(
&env,
ledger_id,
tx_index as u64 + num_mints,
);
};
add_tx_and_verify(&mut in_memory_ledger, 0);

let mut test_broken_upgrade = |ledger_wasm: Vec<u8>| {
env.upgrade_canister(ledger_id, ledger_wasm, upgrade_args.clone())
.unwrap();
let ledger_balance_store_entries =
parse_metric(&env, ledger_id, "ledger_balance_store_entries");
println!("ledger_balance_store_entries: {}", ledger_balance_store_entries);
assert_eq!(ledger_balance_store_entries, 0);
let ledger_num_approvals =
parse_metric(&env, ledger_id, "ledger_num_approvals");
println!("ledger_num_approvals: {}", ledger_num_approvals);
assert_eq!(ledger_num_approvals, 0);
let ledger_total_transactions =
parse_metric(&env, ledger_id, "ledger_total_transactions");
println!("ledger_total_transactions: {}", ledger_total_transactions);
assert_eq!(ledger_total_transactions, 100);
for i in 0..15 {
send_transfer(
&env,
ledger_id,
minter_principal,
&TransferArg {
from_subaccount: None,
to: Account::from(candid::Principal::from(PrincipalId::new_user_test_id(i))),
amount: 1_000_000_u64.into(),
fee: None,
created_at_time: None,
memo: None,
},
).unwrap();
in_memory_ledger.process_mint(
&Account::from(candid::Principal::from(PrincipalId::new_user_test_id(i))),
&Tokens::from(1_000_000_u64)
);
}
let ledger_total_transactions =
parse_metric(&env, ledger_id, "ledger_total_transactions");
println!("ledger_total_transactions: {}", ledger_total_transactions);
assert_eq!(ledger_total_transactions, 115);
let ledger_balance_store_entries =
parse_metric(&env, ledger_id, "ledger_balance_store_entries");
println!("ledger_balance_store_entries: {}", ledger_balance_store_entries);
assert_eq!(ledger_balance_store_entries, 15);
let ledger_num_approvals =
parse_metric(&env, ledger_id, "ledger_num_approvals");
println!("ledger_num_approvals: {}", ledger_num_approvals);
assert_eq!(ledger_num_approvals, 0);
};

let mut test_upgrade = |ledger_wasm: Vec<u8>, expected_migration_steps: u64, in_memory_ledger: &mut InMemoryLedger::<Account, Tokens>| {
env.upgrade_canister(ledger_id, ledger_wasm, upgrade_args.clone())
.unwrap();
wait_ledger_ready(&env, ledger_id, 10);
let stable_upgrade_migration_steps =
parse_metric(&env, ledger_id, "ledger_stable_upgrade_migration_steps");
assert_eq!(stable_upgrade_migration_steps, expected_migration_steps);
add_tx_and_verify(in_memory_ledger, 15);
};

// Go through the broken upgrade path
println!("testing the broken upgrade");
test_broken_upgrade(ledger_wasm_upgrade.clone());

// Test if the old serialized approvals and balances are correctly deserialized
println!("testing the fix upgrade");
test_upgrade(ledger_wasm_fix.clone(), 0, &mut in_memory_ledger);
// Test the new wasm serialization
println!("testing the fix upgrade again");
test_upgrade(ledger_wasm_fix.clone(), 0, &mut in_memory_ledger);
// Test deserializing from memory manager
test_upgrade(ledger_wasm_fix.clone(), 0, &mut in_memory_ledger);
// Test upgrading to the latest official release
test_upgrade(ledger_wasm_v4.clone(), 0, &mut in_memory_ledger);
test_upgrade(ledger_wasm_v4.clone(), 0, &mut in_memory_ledger);

if verify_blocks {
// This will also verify the ledger blocks.
// The current implementation of the InMemoryLedger cannot get blocks
// for the ICP ledger. This part of the test runs only for the ICRC1 ledger.
verify_ledger_state::<Tokens>(&env, ledger_id, None);
}

Ok(())
},
)
.unwrap();
}

pub fn test_upgrade_serialization<Tokens>(
ledger_wasm_mainnet: Vec<u8>,
ledger_wasm_current: Vec<u8>,
Expand Down

0 comments on commit 58c4dd1

Please sign in to comment.