From 37bc808455690a8210d491eebe02c21cbb1d5205 Mon Sep 17 00:00:00 2001 From: "Edward (Mike's bot)" Date: Wed, 29 Apr 2026 00:42:18 +0000 Subject: [PATCH 1/3] fix(token-extensions): migrate quasar-svm to git dep WHAT: Update all 11 token-extensions/*/quasar/Cargo.toml to fetch quasar-svm from the blueshift-gg/quasar-svm git repo, matching every other quasar crate in the repository. WHY: cursor[bot] flagged that token-extensions still pinned quasar-svm = { version = "0.1" } from crates.io while quasar-lang and quasar-spl had been migrated to git deps. Mixing crates.io and git sources for a coordinated trio risks version conflicts and test runtime mismatches. Verified by building + testing basics, cpi-guard, and transfer-fee crates locally - all pass. Addresses cursor[bot] comment #6 on PR #8 (discussion_r3157138724). --- tokens/token-extensions/basics/quasar/Cargo.toml | 2 +- tokens/token-extensions/cpi-guard/quasar/Cargo.toml | 2 +- tokens/token-extensions/default-account-state/quasar/Cargo.toml | 2 +- tokens/token-extensions/group/quasar/Cargo.toml | 2 +- tokens/token-extensions/immutable-owner/quasar/Cargo.toml | 2 +- tokens/token-extensions/interest-bearing/quasar/Cargo.toml | 2 +- tokens/token-extensions/memo-transfer/quasar/Cargo.toml | 2 +- tokens/token-extensions/mint-close-authority/quasar/Cargo.toml | 2 +- tokens/token-extensions/non-transferable/quasar/Cargo.toml | 2 +- tokens/token-extensions/permanent-delegate/quasar/Cargo.toml | 2 +- tokens/token-extensions/transfer-fee/quasar/Cargo.toml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tokens/token-extensions/basics/quasar/Cargo.toml b/tokens/token-extensions/basics/quasar/Cargo.toml index 46facab1..983c74fc 100644 --- a/tokens/token-extensions/basics/quasar/Cargo.toml +++ b/tokens/token-extensions/basics/quasar/Cargo.toml @@ -26,6 +26,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/cpi-guard/quasar/Cargo.toml b/tokens/token-extensions/cpi-guard/quasar/Cargo.toml index 4d700963..9c158e5a 100644 --- a/tokens/token-extensions/cpi-guard/quasar/Cargo.toml +++ b/tokens/token-extensions/cpi-guard/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/default-account-state/quasar/Cargo.toml b/tokens/token-extensions/default-account-state/quasar/Cargo.toml index 2d4d4482..91fe7300 100644 --- a/tokens/token-extensions/default-account-state/quasar/Cargo.toml +++ b/tokens/token-extensions/default-account-state/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/group/quasar/Cargo.toml b/tokens/token-extensions/group/quasar/Cargo.toml index 5c02b0cd..45a9244e 100644 --- a/tokens/token-extensions/group/quasar/Cargo.toml +++ b/tokens/token-extensions/group/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/immutable-owner/quasar/Cargo.toml b/tokens/token-extensions/immutable-owner/quasar/Cargo.toml index f8f48885..3ec07d69 100644 --- a/tokens/token-extensions/immutable-owner/quasar/Cargo.toml +++ b/tokens/token-extensions/immutable-owner/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/interest-bearing/quasar/Cargo.toml b/tokens/token-extensions/interest-bearing/quasar/Cargo.toml index 6e9ec58d..c918193d 100644 --- a/tokens/token-extensions/interest-bearing/quasar/Cargo.toml +++ b/tokens/token-extensions/interest-bearing/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/memo-transfer/quasar/Cargo.toml b/tokens/token-extensions/memo-transfer/quasar/Cargo.toml index 07f0ac8e..2c8abc21 100644 --- a/tokens/token-extensions/memo-transfer/quasar/Cargo.toml +++ b/tokens/token-extensions/memo-transfer/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml b/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml index c6c41957..5f12408a 100644 --- a/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml +++ b/tokens/token-extensions/mint-close-authority/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/non-transferable/quasar/Cargo.toml b/tokens/token-extensions/non-transferable/quasar/Cargo.toml index be7d11b6..b72ebeff 100644 --- a/tokens/token-extensions/non-transferable/quasar/Cargo.toml +++ b/tokens/token-extensions/non-transferable/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml b/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml index 47029902..875193ec 100644 --- a/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml +++ b/tokens/token-extensions/permanent-delegate/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } diff --git a/tokens/token-extensions/transfer-fee/quasar/Cargo.toml b/tokens/token-extensions/transfer-fee/quasar/Cargo.toml index 90775637..cfa93d5a 100644 --- a/tokens/token-extensions/transfer-fee/quasar/Cargo.toml +++ b/tokens/token-extensions/transfer-fee/quasar/Cargo.toml @@ -25,6 +25,6 @@ quasar-spl = { git = "https://github.com/blueshift-gg/quasar", branch = "master" solana-instruction = { version = "3.2.0" } [dev-dependencies] -quasar-svm = { version = "0.1" } +quasar-svm = { git = "https://github.com/blueshift-gg/quasar-svm" } spl-token-interface = { version = "2.0.0" } solana-program-pack = { version = "3.1.0" } From ddea756d9b45f6f8255d399bb74c745f3fb8cf90 Mon Sep 17 00:00:00 2001 From: "Edward (Mike's bot)" Date: Wed, 29 Apr 2026 00:49:17 +0000 Subject: [PATCH 2/3] fix(cpi/lever): migrate to current Quasar API WHAT: Update the lever program (basics/cross-program-invocation/quasar/lever) to compile against the current quasar-lang and quasar-spl APIs: - Drop `<'info>` lifetime parameters from account context structs - Replace `&'info mut Signer` / `&'info mut Account<...>` / `&'info Program<...>` reference fields with their owned counterparts (`Signer`, `Account<...>`, `Program<...>`) - Move PDA seed declaration onto the state struct via `#[seeds(b"power")]` and reference it as `seeds = PowerStatus::seeds()` in the accounts derive - Mark `PowerStatus` with `set_inner` and call `set_inner(PowerStatusInner { .. })` from the initialize handler (matches the counter pattern for fixed-size Pod accounts) - Bind the `name` instruction arg to `String<50>` (Quasar's PodString needs a capacity generic; plain `String` no longer compiles) WHY: cursor[bot] flagged the lever crate as still using the pre-migration Quasar API even after PR #8 updated lever's Cargo.toml. The crate is excluded from CI via .ghaignore (the workflow expects a root Quasar.toml per project but cross-program-invocation/quasar uses hand/ + lever/ subdirectories), so the breakage was masked. Verified locally: `quasar build && cargo test --release` passes for both lever (4 tests) and hand (3 tests). Addresses cursor[bot] comment #8 on PR #8 (discussion_r3157509603). --- .../quasar/lever/src/instructions/initialize.rs | 16 ++++++++-------- .../lever/src/instructions/switch_power.rs | 4 ++-- .../quasar/lever/src/lib.rs | 2 +- .../quasar/lever/src/state.rs | 4 +++- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/basics/cross-program-invocation/quasar/lever/src/instructions/initialize.rs b/basics/cross-program-invocation/quasar/lever/src/instructions/initialize.rs index 52736034..832a8732 100644 --- a/basics/cross-program-invocation/quasar/lever/src/instructions/initialize.rs +++ b/basics/cross-program-invocation/quasar/lever/src/instructions/initialize.rs @@ -1,21 +1,21 @@ use { - crate::state::PowerStatus, + crate::state::{PowerStatus, PowerStatusInner}, quasar_lang::prelude::*, }; /// Accounts for initialising the power status (PDA seeded by "power"). #[derive(Accounts)] -pub struct InitializeLever<'info> { +pub struct InitializeLever { #[account(mut)] - pub payer: &'info mut Signer, - #[account(mut, init, payer = payer, seeds = [b"power"], bump)] - pub power: &'info mut Account, - pub system_program: &'info Program, + pub payer: Signer, + #[account(mut, init, payer = payer, seeds = PowerStatus::seeds(), bump)] + pub power: Account, + pub system_program: Program, } #[inline(always)] pub fn handle_initialize(accounts: &mut InitializeLever) -> Result<(), ProgramError> { - // Power starts off (false). - accounts.power.set_inner(PodBool::from(false)); + // Power starts off (false). Counter-style fixed-size set_inner takes only the inner value. + accounts.power.set_inner(PowerStatusInner { is_on: PodBool::from(false) }); Ok(()) } diff --git a/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs b/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs index d5f376c1..513506e8 100644 --- a/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs +++ b/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs @@ -5,9 +5,9 @@ use { /// Accounts for toggling the power switch. #[derive(Accounts)] -pub struct SwitchPower<'info> { +pub struct SwitchPower { #[account(mut)] - pub power: &'info mut Account, + pub power: Account, } #[inline(always)] diff --git a/basics/cross-program-invocation/quasar/lever/src/lib.rs b/basics/cross-program-invocation/quasar/lever/src/lib.rs index 00aa9464..1922feca 100644 --- a/basics/cross-program-invocation/quasar/lever/src/lib.rs +++ b/basics/cross-program-invocation/quasar/lever/src/lib.rs @@ -22,7 +22,7 @@ mod quasar_lever { /// Toggle the power switch. Logs who is pulling the lever. #[instruction(discriminator = 1)] - pub fn switch_power(ctx: Ctx, name: String) -> Result<(), ProgramError> { + pub fn switch_power(ctx: Ctx, name: String<50>) -> Result<(), ProgramError> { instructions::handle_switch_power(&mut ctx.accounts, name) } } diff --git a/basics/cross-program-invocation/quasar/lever/src/state.rs b/basics/cross-program-invocation/quasar/lever/src/state.rs index 4b4cc2ab..84610a4f 100644 --- a/basics/cross-program-invocation/quasar/lever/src/state.rs +++ b/basics/cross-program-invocation/quasar/lever/src/state.rs @@ -1,7 +1,9 @@ use quasar_lang::prelude::*; /// Onchain power status: a single boolean toggle. -#[account(discriminator = 1)] +/// Derived as a PDA from the seed "power" (single global account). +#[account(discriminator = 1, set_inner)] +#[seeds(b"power")] pub struct PowerStatus { pub is_on: PodBool, } From 6ec7de121bfcfc9084fc29d0b4952747432a28db Mon Sep 17 00:00:00 2001 From: Mike MacCana Date: Wed, 29 Apr 2026 01:31:45 +0000 Subject: [PATCH 3/3] fix(cpi/hand): use u8 length prefix for String<50> in CPI wire format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lever's switch_power instruction takes `String<50>`, which Quasar serialises with a single-byte length prefix (matching every other Quasar program: account-data, close-account, rent, realloc, repository-layout). The hand program's pull_lever CPI builder was manually constructing instruction data with a u32 (4-byte) length prefix, so every hand→lever CPI call sent a malformed payload. The breakage was masked because the lever's handler ignored the deserialised name (`_name`), but the value itself was corrupted — e.g. "\\0\\0\\0Al" instead of "Alice". The lever's own tests.rs had the same stale u32 prefix in its instruction-data builder, and hand's tests.rs had it for inbound pull_lever data too. Both now use `data.push(name.len() as u8)`, matching the canonical pattern used across the Quasar example suite. To keep this from regressing again, the lever now logs the deserialised name and both test suites assert that the round-tripped name appears in program logs verbatim ("Alice" / "Bob"). A stale length prefix on either leg of the CPI would surface immediately as a corrupted log line. Files changed: - hand/src/instructions/pull_lever.rs (CPI builder: u32 → u8) - hand/src/tests.rs (inbound builder: u32 → u8, name assert) - lever/src/instructions/switch_power.rs (log name) - lever/src/tests.rs (test builder: u32 → u8, name assert) --- .../hand/src/instructions/pull_lever.rs | 25 +++++++++++-------- .../quasar/hand/src/tests.rs | 25 ++++++++++++++++--- .../lever/src/instructions/switch_power.rs | 7 +++++- .../quasar/lever/src/tests.rs | 25 ++++++++++++++++--- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs b/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs index 7b15184c..f602af29 100644 --- a/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs +++ b/basics/cross-program-invocation/quasar/hand/src/instructions/pull_lever.rs @@ -15,24 +15,27 @@ pub struct PullLever { pub fn handle_pull_lever(accounts: &PullLever, name: &str) -> Result<(), ProgramError> { log("Hand is pulling the lever!"); - // Build the switch_power instruction data for the lever program: - // [disc=1] [name: u32 len + bytes] - // 128 bytes is enough for any reasonable name. + // Build the switch_power instruction data for the lever program. + // + // Wire format: [discriminator = 1] [name: u8 length prefix + bytes]. + // + // The lever's switch_power instruction takes `String<50>`, which Quasar + // serialises with a single-byte length prefix (matching every other + // Quasar program: account-data, close-account, rent, realloc, + // repository-layout). An earlier version of this builder used a u32 + // length prefix, which sent a malformed payload on every CPI call. + // + // 128 bytes is enough for any reasonable name (max 50 + 1 + 1 = 52). let mut data = [0u8; 128]; let name_bytes = name.as_bytes(); - let data_len = 1 + 4 + name_bytes.len(); + let data_len = 1 + 1 + name_bytes.len(); data[0] = 1; - - let len_bytes = (name_bytes.len() as u32).to_le_bytes(); - data[1] = len_bytes[0]; - data[2] = len_bytes[1]; - data[3] = len_bytes[2]; - data[4] = len_bytes[3]; + data[1] = name_bytes.len() as u8; let mut i = 0; while i < name_bytes.len() { - data[5 + i] = name_bytes[i]; + data[2 + i] = name_bytes[i]; i += 1; } diff --git a/basics/cross-program-invocation/quasar/hand/src/tests.rs b/basics/cross-program-invocation/quasar/hand/src/tests.rs index 8ec1c323..05ede556 100644 --- a/basics/cross-program-invocation/quasar/hand/src/tests.rs +++ b/basics/cross-program-invocation/quasar/hand/src/tests.rs @@ -30,10 +30,17 @@ fn power_account(address: Pubkey, is_on: bool) -> Account { } /// Build pull_lever instruction data (discriminator = 0). -/// Wire format: [disc=0] [name: String] +/// +/// Wire format: [discriminator = 0] [name: u8 length prefix + bytes]. +/// +/// The hand's pull_lever instruction takes `String<50>`, which Quasar +/// serialises with a single-byte length prefix. The CPI builder in +/// `pull_lever.rs` re-serialises the same name into the lever's +/// instruction data using the same u8 prefix. fn build_pull_lever(name: &str) -> Vec { - let mut data = vec![0u8]; // discriminator = 0 - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + let mut data = Vec::with_capacity(2 + name.len()); + data.push(0u8); // discriminator = 0 + data.push(name.len() as u8); data.extend_from_slice(name.as_bytes()); data } @@ -72,6 +79,14 @@ fn test_pull_lever_turns_on() { assert!(logs.contains("Hand is pulling"), "hand should log"); assert!(logs.contains("pulling the power switch"), "lever should log"); assert!(logs.contains("now on"), "power should turn on"); + // Verifies the CPI wire format: the lever logs the name it + // deserialised. A stale u32 length prefix on either the inbound + // `pull_lever` payload or the CPI to `switch_power` would corrupt + // this (e.g. "\0\0\0Al" instead of "Alice"). + assert!( + logs.contains("Alice"), + "name should round-trip through hand → lever CPI; logs: {logs}" + ); let account = result.account(&power_addr).unwrap(); assert_eq!(account.data[1], 1, "power should be on"); @@ -107,6 +122,10 @@ fn test_pull_lever_turns_off() { let logs = result.logs.join("\n"); assert!(logs.contains("now off"), "power should turn off"); + assert!( + logs.contains("Bob"), + "name should round-trip through hand → lever CPI; logs: {logs}" + ); let account = result.account(&power_addr).unwrap(); assert_eq!(account.data[1], 0, "power should be off"); diff --git a/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs b/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs index 513506e8..52ac4401 100644 --- a/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs +++ b/basics/cross-program-invocation/quasar/lever/src/instructions/switch_power.rs @@ -11,13 +11,18 @@ pub struct SwitchPower { } #[inline(always)] -pub fn handle_switch_power(accounts: &mut SwitchPower, _name: &str) -> Result<(), ProgramError> { +pub fn handle_switch_power(accounts: &mut SwitchPower, name: &str) -> Result<(), ProgramError> { let current: bool = accounts.power.is_on.into(); let new_state = !current; accounts.power.is_on = PodBool::from(new_state); // Quasar's log() takes &str — no format! in no_std. + // Logging the name verifies the wire format end-to-end: a stale u32 + // length prefix would surface here as a corrupted name (e.g. the + // first three bytes parsed as zeros, leaving "\0\0\0Al" instead of + // "Alice"). log("Someone is pulling the power switch!"); + log(name); if new_state { log("The power is now on."); diff --git a/basics/cross-program-invocation/quasar/lever/src/tests.rs b/basics/cross-program-invocation/quasar/lever/src/tests.rs index b6005e4a..ed2c32e1 100644 --- a/basics/cross-program-invocation/quasar/lever/src/tests.rs +++ b/basics/cross-program-invocation/quasar/lever/src/tests.rs @@ -47,10 +47,19 @@ fn build_initialize() -> Vec { } /// Build switch_power instruction data (discriminator = 1). -/// Wire format: [disc=1] [name: String] +/// +/// Wire format: [discriminator = 1] [name: u8 length prefix + bytes]. +/// +/// The lever's switch_power instruction takes `String<50>`, which Quasar +/// serialises with a single-byte length prefix (matching every other +/// Quasar program: account-data, close-account, rent, realloc, +/// repository-layout). An earlier version of this builder used a u32 +/// length prefix, which produced a malformed payload that happened to +/// pass because the handler ignored the deserialised name. fn build_switch_power(name: &str) -> Vec { - let mut data = vec![1u8]; // discriminator = 1 - data.extend_from_slice(&(name.len() as u32).to_le_bytes()); + let mut data = Vec::with_capacity(2 + name.len()); + data.push(1u8); // discriminator = 1 + data.push(name.len() as u8); data.extend_from_slice(name.as_bytes()); data } @@ -104,6 +113,12 @@ fn test_switch_power_on() { let logs = result.logs.join("\n"); assert!(logs.contains("pulling the power switch"), "should log switch"); assert!(logs.contains("now on"), "should say power is on"); + // Verifies wire format: a stale u32 length prefix would corrupt the + // deserialised name (e.g. "\0\0\0Al" instead of "Alice"). + assert!( + logs.contains("Alice"), + "deserialised name should round-trip exactly; logs: {logs}" + ); let account = result.account(&power_addr).unwrap(); assert_eq!(account.data[1], 1, "power should now be on"); @@ -128,6 +143,10 @@ fn test_switch_power_off() { let logs = result.logs.join("\n"); assert!(logs.contains("now off"), "should say power is off"); + assert!( + logs.contains("Bob"), + "deserialised name should round-trip exactly; logs: {logs}" + ); let account = result.account(&power_addr).unwrap(); assert_eq!(account.data[1], 0, "power should now be off");