From 5a6fd15d83fca60e69b32c3e9e14e89f0d42de0c Mon Sep 17 00:00:00 2001 From: Stan Drozd Date: Thu, 18 Aug 2022 14:44:50 -0700 Subject: [PATCH] pyth2wormhole: Fix a cfg migration bug, fix cfg lockout (see below) This commit resolves a runtime problem in migrate() which occurred on devnet, as well as invalid mutability for the old config and misuse of the checked_sub() method. The runtime problem came from a non-zero balance existing on not-yet-used PDA. Effectively, this means permissionless initialization of PDAs on Solana. Anyone can send lamports to any account on Solana (existing or not), and it doesn't take much funds to keep an empty account exempt. While it is possible to recover from it, this case is relatively rare and takes a lot of code to automate. Instead, we settle for a dumb bump of the config PDA seed (see config.rs). This measure is best used sparingly, as it imposes the same static seed on all SOL networks. This will cause headaches if the attester tooling grows a third-party user base. --- solana/pyth2wormhole/client/src/lib.rs | 2 +- solana/pyth2wormhole/program/src/config.rs | 7 ++++++- solana/pyth2wormhole/program/src/migrate.rs | 6 ++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/solana/pyth2wormhole/client/src/lib.rs b/solana/pyth2wormhole/client/src/lib.rs index 210a8fa48a..360e0b97da 100644 --- a/solana/pyth2wormhole/client/src/lib.rs +++ b/solana/pyth2wormhole/client/src/lib.rs @@ -143,7 +143,7 @@ pub fn gen_migrate_tx( let accs = MigrateAccounts { new_config: Derived(p2w_addr), - old_config: DerivedRO(p2w_addr), + old_config: Derived(p2w_addr), current_owner: Signer(owner), payer: Signer(payer), }; diff --git a/solana/pyth2wormhole/program/src/config.rs b/solana/pyth2wormhole/program/src/config.rs index 922fb65561..2adc081b72 100644 --- a/solana/pyth2wormhole/program/src/config.rs +++ b/solana/pyth2wormhole/program/src/config.rs @@ -91,8 +91,13 @@ pub struct Pyth2WormholeConfigV2 { pub is_active: bool, } +/// Note: If you get stuck with a pre-existing config account +/// (e.g. someone transfers into a PDA that we're not using yet), it's +/// usually easier to change the seed slightly +/// (e.g. pyth2wormhole-config-v2 -> pyth2wormhole-config-v2.1). This +/// saves a lot of time coding around this edge case. pub type P2WConfigAccountV2<'b, const IsInitialized: AccountState> = - Derive, "pyth2wormhole-config-v2">; + Derive, "pyth2wormhole-config-v2.1">; impl From for Pyth2WormholeConfigV2 { fn from(old: Pyth2WormholeConfigV1) -> Self { diff --git a/solana/pyth2wormhole/program/src/migrate.rs b/solana/pyth2wormhole/program/src/migrate.rs index 4035e7ad2d..1c80a34002 100644 --- a/solana/pyth2wormhole/program/src/migrate.rs +++ b/solana/pyth2wormhole/program/src/migrate.rs @@ -38,7 +38,7 @@ pub struct Migrate<'b> { /// New config account to be populated. Must be unused. pub new_config: Mut>, /// Old config using the previous format. - pub old_config: OldP2WConfigAccount<'b>, + pub old_config: Mut>, /// Current owner authority of the program pub current_owner: Mut>>, /// Payer account for updating the account data @@ -78,7 +78,7 @@ pub fn migrate(ctx: &ExecutionContext, accs: &mut Migrate, data: ()) -> SoliResu **accs.old_config.info().lamports.borrow_mut() = 0; // Credit payer with saved balance - accs.payer + let new_payer_balance = accs.payer .info() .lamports .borrow_mut() @@ -88,5 +88,7 @@ pub fn migrate(ctx: &ExecutionContext, accs: &mut Migrate, data: ()) -> SoliResu SolitaireError::ProgramError(ProgramError::Custom(0xDEADBEEF)) })?; + **accs.payer.info().lamports.borrow_mut() = new_payer_balance; + Ok(()) }