diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index 64b9a7e65..9fa9f2a3a 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -479,6 +479,43 @@ mod tests { assert_eq!(to_account.borrow().data, [0, 0]); } + #[test] + fn test_create_account_with_seed_separate_base_account() { + let new_owner = Pubkey::new(&[9; 32]); + let from = solana_sdk::pubkey::new_rand(); + let base = solana_sdk::pubkey::new_rand(); + let seed = "shiny pepper"; + let to = Pubkey::create_with_seed(&base, seed, &new_owner).unwrap(); + + let from_account = Account::new_ref(100, 0, &system_program::id()); + let to_account = Account::new_ref(0, 0, &Pubkey::default()); + let base_account = Account::new_ref(0, 0, &Pubkey::default()); + + assert_eq!( + process_instruction( + &Pubkey::default(), + &[ + KeyedAccount::new(&from, true, &from_account), + KeyedAccount::new(&to, false, &to_account), + KeyedAccount::new(&base, true, &base_account) + ], + &bincode::serialize(&SystemInstruction::CreateAccountWithSeed { + base, + seed: seed.to_string(), + lamports: 50, + space: 2, + owner: new_owner + }) + .unwrap() + ), + Ok(()) + ); + assert_eq!(from_account.borrow().lamports, 50); + assert_eq!(to_account.borrow().lamports, 50); + assert_eq!(to_account.borrow().owner, new_owner); + assert_eq!(to_account.borrow().data, [0, 0]); + } + #[test] fn test_address_create_with_seed_mismatch() { let from = solana_sdk::pubkey::new_rand(); diff --git a/sdk/program/src/system_instruction.rs b/sdk/program/src/system_instruction.rs index adc38e697..1cd1453a1 100644 --- a/sdk/program/src/system_instruction.rs +++ b/sdk/program/src/system_instruction.rs @@ -92,7 +92,9 @@ pub enum SystemInstruction { /// # Account references /// 0. [WRITE, SIGNER] Funding account /// 1. [WRITE] Created account - /// 2. [SIGNER] Base account + /// 2. [SIGNER] (optional) Base account; the account matching the base Pubkey below must be + /// provided as a signer, but may be the same as the funding account + /// and provided as account 0 CreateAccountWithSeed { /// Base public key base: Pubkey, diff --git a/transaction-status/src/parse_system.rs b/transaction-status/src/parse_system.rs index d900e147f..eb849fbe0 100644 --- a/transaction-status/src/parse_system.rs +++ b/transaction-status/src/parse_system.rs @@ -68,12 +68,12 @@ pub fn parse_system( space, owner, } => { - check_num_system_accounts(&instruction.accounts, 3)?; + check_num_system_accounts(&instruction.accounts, 2)?; Ok(ParsedInstructionEnum { instruction_type: "createAccountWithSeed".to_string(), info: json!({ "source": account_keys[instruction.accounts[0] as usize].to_string(), - "newAccount": account_keys[instruction.accounts[2] as usize].to_string(), + "newAccount": account_keys[instruction.accounts[1] as usize].to_string(), "base": base.to_string(), "seed": seed, "lamports": lamports, @@ -260,7 +260,7 @@ mod test { let seed = "test_seed"; let instruction = system_instruction::create_account_with_seed( - &keys[0], &keys[1], &keys[2], seed, lamports, space, &keys[3], + &keys[0], &keys[2], &keys[1], seed, lamports, space, &keys[3], ); let message = Message::new(&[instruction], None); assert_eq!( @@ -269,16 +269,37 @@ mod test { instruction_type: "createAccountWithSeed".to_string(), info: json!({ "source": keys[0].to_string(), - "newAccount": keys[1].to_string(), + "newAccount": keys[2].to_string(), "lamports": lamports, - "base": keys[2].to_string(), + "base": keys[1].to_string(), "seed": seed, "owner": keys[3].to_string(), "space": space, }), } ); - assert!(parse_system(&message.instructions[0], &keys[0..2]).is_err()); + + let seed = "test_seed"; + let instruction = system_instruction::create_account_with_seed( + &keys[0], &keys[1], &keys[0], seed, lamports, space, &keys[3], + ); + let message = Message::new(&[instruction], None); + assert_eq!( + parse_system(&message.instructions[0], &keys[0..2]).unwrap(), + ParsedInstructionEnum { + instruction_type: "createAccountWithSeed".to_string(), + info: json!({ + "source": keys[0].to_string(), + "newAccount": keys[1].to_string(), + "lamports": lamports, + "base": keys[0].to_string(), + "seed": seed, + "owner": keys[3].to_string(), + "space": space, + }), + } + ); + assert!(parse_system(&message.instructions[0], &keys[0..1]).is_err()); let instruction = system_instruction::allocate(&keys[0], space); let message = Message::new(&[instruction], None);