From f46b4506e78462f61a21414e27e7d06556ff0370 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 31 Aug 2020 21:51:52 -0700 Subject: [PATCH] Ensure that the spl-token 2 native mint account is owned by the spl-token 2 program. Workaround for https://github.com/solana-labs/solana-program-library/issues/374 until spl-token 3 is shipped --- core/src/rpc.rs | 6 +- runtime/src/bank.rs | 144 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 7a8b134fdca205..2aaf431d352dbb 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -2873,7 +2873,7 @@ pub mod tests { let largest_accounts: Vec = serde_json::from_value(json["result"]["value"].clone()) .expect("actual response deserialization"); - assert_eq!(largest_accounts.len(), 19); + assert_eq!(largest_accounts.len(), 20); // Get Alice balance let req = format!( @@ -2910,7 +2910,7 @@ pub mod tests { let largest_accounts: Vec = serde_json::from_value(json["result"]["value"].clone()) .expect("actual response deserialization"); - assert_eq!(largest_accounts.len(), 18); + assert_eq!(largest_accounts.len(), 19); let req = r#"{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts","params":[{"filter":"nonCirculating"}]}"#; let res = io.handle_request_sync(&req, meta); let json: Value = serde_json::from_str(&res.unwrap()).unwrap(); @@ -4906,7 +4906,7 @@ pub mod tests { .expect("actual response deserialization"); let accounts: Vec = serde_json::from_value(result["result"].clone()).unwrap(); - assert_eq!(accounts.len(), 3); + assert_eq!(accounts.len(), 4); // Test returns only mint accounts let req = format!( diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 35a573cc650b20..0102a95909dc68 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -71,6 +71,29 @@ use std::{ sync::{Arc, RwLock, RwLockReadGuard}, }; +// Partial SPL Token v2.0.x declarations inlined to avoid an external dependency on the spl-token crate +pub mod inline_spl_token_v2_0 { + solana_sdk::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); + pub mod native_mint { + solana_sdk::declare_id!("So11111111111111111111111111111111111111112"); + + /* + Mint { + mint_authority: COption::None, + supply: 0, + decimals: 9, + is_initialized: true, + freeze_authority: COption::None, + } + */ + pub const ACCOUNT_DATA: [u8; 82] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + } +} + pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0; pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5; @@ -3208,6 +3231,7 @@ impl Bank { self.reinvoke_entered_epoch_callback(initiate_callback); self.recheck_cross_program_support(); self.recheck_compute_budget(); + self.reconfigure_token2_native_mint(); } fn ensure_builtins(&mut self, init_or_warp: bool) { @@ -3257,6 +3281,49 @@ impl Bank { self.set_compute_budget(compute_budget); } + fn reconfigure_token2_native_mint(self: &mut Bank) { + let reconfigure_token2_native_mint = match self.operating_mode() { + OperatingMode::Development => true, + OperatingMode::Preview => self.epoch() == 95, + OperatingMode::Stable => self.epoch() == 75, + }; + + if reconfigure_token2_native_mint { + let mut native_mint_account = solana_sdk::account::Account { + owner: inline_spl_token_v2_0::id(), + data: inline_spl_token_v2_0::native_mint::ACCOUNT_DATA.to_vec(), + lamports: 1000000000, // 1 SOL + executable: false, + rent_epoch: self.epoch() + 1, + }; + + // As a workaround for + // https://github.com/solana-labs/solana-program-library/issues/374, ensure that the + // spl-token 2 native mint account is owned by the spl-token 2 program. + let store = if let Some(existing_native_mint_account) = + self.get_account(&inline_spl_token_v2_0::native_mint::id()) + { + if existing_native_mint_account.owner == solana_sdk::system_program::id() { + native_mint_account.lamports = existing_native_mint_account.lamports; + true + } else { + false + } + } else { + self.capitalization + .fetch_add(native_mint_account.lamports, Ordering::Relaxed); + true + }; + + if store { + self.store_account( + &inline_spl_token_v2_0::native_mint::id(), + &native_mint_account, + ); + } + } + } + fn fix_recent_blockhashes_sysvar_delay(&self) -> bool { let activation_slot = match self.operating_mode() { OperatingMode::Development => 0, @@ -8008,6 +8075,7 @@ mod tests { &[], ); genesis_config.creation_time = 0; + genesis_config.operating_mode = OperatingMode::Stable; let mut bank = Arc::new(Bank::new(&genesis_config)); // Check a few slots, cross an epoch boundary assert_eq!(bank.get_slots_in_epoch(0), 32); @@ -8016,25 +8084,25 @@ mod tests { if bank.slot == 0 { assert_eq!( bank.hash().to_string(), - "DJ5664svVgjZ8sRLZSrdYAjaAzJe3aEGVBDpZEeoZJ5u" + "HrxvKJxPhzgXgoJ2Rg91acrXWki6SErJk1sfxfTDWsZt" ); } if bank.slot == 32 { assert_eq!( bank.hash().to_string(), - "GDH7kUpcQuMT23pPeU9vZdmyMSPQPwzoqdNgFaLga7x3" + "AemCVcpsULuA76fpDYzs74futtMQtNNiF1gz3VSVP4AS" ); } if bank.slot == 64 { assert_eq!( bank.hash().to_string(), - "J4L6bT3KnMMXSufcUSy6Lg9TNi2pFVsYNvQ1Fzms2j1Z" + "4ECxp4u4SRwn2w7YUj28nnADMx7kQ2gYRB7PA617eWu6" ); } if bank.slot == 128 { assert_eq!( bank.hash().to_string(), - "BiCUyj8PsbsLW79waf1ifr3wDuZSFwLBhTkdbgHFjrtJ" + "AeHGi2VWQ7gWh6KkMQjrhY1ZrLUedgMxfvPRR82dyg6L" ); break; } @@ -8125,7 +8193,7 @@ mod tests { .map(|_| bank.process_stale_slot_with_budget(0, force_to_return_alive_account)) .collect::>(); consumed_budgets.sort(); - assert_eq!(consumed_budgets, vec![0, 1, 8]); + assert_eq!(consumed_budgets, vec![0, 1, 9]); } #[test] @@ -8360,4 +8428,70 @@ mod tests { .unwrap() .add_native_program("mock_program", &program_id); } + + #[test] + fn test_reconfigure_token2_native_mint() { + solana_logger::setup(); + + let mut genesis_config = + create_genesis_config_with_leader(5, &Pubkey::new_rand(), 0).genesis_config; + + // OperatingMode::Development - Native mint exists immediately + assert_eq!(genesis_config.operating_mode, OperatingMode::Development); + let bank = Arc::new(Bank::new(&genesis_config)); + assert_eq!( + bank.get_balance(&inline_spl_token_v2_0::native_mint::id()), + 1000000000 + ); + + // OperatingMode::Preview - Native mint blinks into existence at epoch 95 + genesis_config.operating_mode = OperatingMode::Preview; + let bank = Arc::new(Bank::new(&genesis_config)); + assert_eq!( + bank.get_balance(&inline_spl_token_v2_0::native_mint::id()), + 0 + ); + bank.deposit(&inline_spl_token_v2_0::native_mint::id(), 4200000000); + + let bank = Bank::new_from_parent( + &bank, + &Pubkey::default(), + genesis_config.epoch_schedule.get_first_slot_in_epoch(95), + ); + + let native_mint_account = bank + .get_account(&inline_spl_token_v2_0::native_mint::id()) + .unwrap(); + assert_eq!(native_mint_account.data.len(), 82); + assert_eq!( + bank.get_balance(&inline_spl_token_v2_0::native_mint::id()), + 4200000000 + ); + assert_eq!(native_mint_account.owner, inline_spl_token_v2_0::id()); + + // OperatingMode::Stable - Native mint blinks into existence at epoch 75 + genesis_config.operating_mode = OperatingMode::Stable; + let bank = Arc::new(Bank::new(&genesis_config)); + assert_eq!( + bank.get_balance(&inline_spl_token_v2_0::native_mint::id()), + 0 + ); + bank.deposit(&inline_spl_token_v2_0::native_mint::id(), 4200000000); + + let bank = Bank::new_from_parent( + &bank, + &Pubkey::default(), + genesis_config.epoch_schedule.get_first_slot_in_epoch(75), + ); + + let native_mint_account = bank + .get_account(&inline_spl_token_v2_0::native_mint::id()) + .unwrap(); + assert_eq!(native_mint_account.data.len(), 82); + assert_eq!( + bank.get_balance(&inline_spl_token_v2_0::native_mint::id()), + 4200000000 + ); + assert_eq!(native_mint_account.owner, inline_spl_token_v2_0::id()); + } }