From aeb55aa62cded3cd6811d4bbdd3392324eac8014 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 (cherry picked from commit 7341e600434df5465268dae40b4635cc09220328) --- core/src/non_circulating_supply.rs | 5 +- core/src/rpc.rs | 6 +- core/src/rpc_service.rs | 7 +- programs/bpf/Cargo.lock | 10 ++ runtime/src/bank.rs | 152 +++++++++++++++++++++++++++-- 5 files changed, 168 insertions(+), 12 deletions(-) diff --git a/core/src/non_circulating_supply.rs b/core/src/non_circulating_supply.rs index cbc854f2719ff9..bb17f98430f80f 100644 --- a/core/src/non_circulating_supply.rs +++ b/core/src/non_circulating_supply.rs @@ -96,7 +96,9 @@ solana_sdk::pubkeys!( mod tests { use super::*; use solana_sdk::{ - account::Account, epoch_schedule::EpochSchedule, genesis_config::GenesisConfig, + account::Account, + epoch_schedule::EpochSchedule, + genesis_config::{GenesisConfig, OperatingMode}, }; use solana_stake_program::stake_state::{Authorized, Lockup, Meta, StakeState}; use std::{collections::BTreeMap, sync::Arc}; @@ -147,6 +149,7 @@ mod tests { let genesis_config = GenesisConfig { accounts, epoch_schedule: EpochSchedule::new(slots_per_epoch), + operating_mode: OperatingMode::Stable, ..GenesisConfig::default() }; let mut bank = Arc::new(Bank::new(&genesis_config)); diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 51c0d15f39777f..783366a657fefd 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -2855,7 +2855,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!( @@ -2892,7 +2892,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(); @@ -4853,7 +4853,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/core/src/rpc_service.rs b/core/src/rpc_service.rs index cf3ffdb5540535..270bbc747fca9a 100644 --- a/core/src/rpc_service.rs +++ b/core/src/rpc_service.rs @@ -385,7 +385,7 @@ mod tests { snapshot_utils::SnapshotVersion, }; use solana_runtime::bank::Bank; - use solana_sdk::signature::Signer; + use solana_sdk::{genesis_config::OperatingMode, signature::Signer}; use std::net::{IpAddr, Ipv4Addr}; #[test] @@ -440,7 +440,10 @@ mod tests { } fn create_bank_forks() -> Arc> { - let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); + let GenesisConfigInfo { + mut genesis_config, .. + } = create_genesis_config(10_000); + genesis_config.operating_mode = OperatingMode::Stable; let bank = Bank::new(&genesis_config); Arc::new(RwLock::new(BankForks::new(bank))) } diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 9bc12df62bdf7f..bc2e0a71ef54ec 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -224,6 +224,16 @@ dependencies = [ "byteorder 1.3.4", ] +[[package]] +name = "crossbeam-channel" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.7.3" diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 29d575aeeda42b..df9abda449df0f 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -45,7 +45,9 @@ use solana_sdk::{ hash::{extend_and_hash, hashv, Hash}, incinerator, inflation::Inflation, - native_loader, nonce, + native_loader, + native_token::sol_to_lamports, + nonce, program_utils::limited_deserialize, pubkey::Pubkey, sanitize::Sanitize, @@ -70,6 +72,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; @@ -483,6 +508,7 @@ impl Bank { new.ancestors.insert(p.slot(), i + 1); }); + new.reconfigure_token2_native_mint(); new.update_slot_hashes(); new.update_rewards(parent.epoch()); new.update_stake_history(Some(parent.epoch())); @@ -2334,6 +2360,7 @@ impl Bank { for program in builtin_programs.iter() { self.add_builtin_program(&program.name, program.id, program.process_instruction); } + self.reconfigure_token2_native_mint(); } pub fn init_rent_collector_after_deserialize(&mut self, genesis_config: &GenesisConfig) { @@ -2877,6 +2904,49 @@ impl Bank { consumed_budget.saturating_sub(budget_recovery_delta) } + 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: sol_to_lamports(1.), + 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, @@ -3087,6 +3157,7 @@ mod tests { accounts: (0..42) .map(|_| (Pubkey::new_rand(), Account::new(42, 0, &Pubkey::default()))) .collect(), + operating_mode: OperatingMode::Stable, ..GenesisConfig::default() })); assert_eq!(bank.capitalization(), 42 * 42); @@ -4552,6 +4623,7 @@ mod tests { hashes_per_tick: None, target_tick_count: None, }, + operating_mode: OperatingMode::Stable, ..GenesisConfig::default() })); @@ -4663,6 +4735,7 @@ mod tests { hashes_per_tick: None, target_tick_count: None, }, + operating_mode: OperatingMode::Stable, ..GenesisConfig::default() })); @@ -7653,6 +7726,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); @@ -7661,25 +7735,25 @@ mod tests { if bank.slot == 0 { assert_eq!( bank.hash().to_string(), - "HsNNxYe9FjPZtW8zNwSrLsB6d8YXoWqhpegE328C5Wvy", + "A1pQjC4aGvK5iokQztbwHbeswkCzjkoebkSWc47ctRsK" ); } if bank.slot == 32 { assert_eq!( bank.hash().to_string(), - "9rsnmUCTg2wFnKVnaUSEQcSicvPUyXPTmbsakB2o3eTu" + "J7NjxvfySQDqMNNJRUcWRvczjEv2TjHgEzJ6seehwPFN" ); } if bank.slot == 64 { assert_eq!( bank.hash().to_string(), - "B1JNAeiR89kcqwqeSSQXFN3spcYW2qVJwuu9hQ9dxn1V" + "8pfF9QbZxdW1SS51tF5XqjFyMipis5iai6KT2xCKgm66" ); } if bank.slot == 128 { assert_eq!( bank.hash().to_string(), - "9iUEmDnWQmjtkoMuR3hJAwQMpCGwHaJAEsfK131rww8y" + "9D3YWZ2dpL1fgUo4JMGLfuDzsz64kVqpxiMFmqmGDK5F" ); break; } @@ -7770,7 +7844,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] @@ -7864,4 +7938,70 @@ mod tests { ); assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 496); // no transaction fee charged } + + #[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()); + } }