Ensure that the spl-token 2 native mint account is owned by the spl-token 2 program. (#11973)
Workaround for https://github.com/solana-labs/solana-program-library/issues/374 until spl-token 3 is shipped
(cherry picked from commit 7341e60043
)
Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
@ -96,7 +96,9 @@ solana_sdk::pubkeys!(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_sdk::{
|
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 solana_stake_program::stake_state::{Authorized, Lockup, Meta, StakeState};
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
@ -147,6 +149,7 @@ mod tests {
|
|||||||
let genesis_config = GenesisConfig {
|
let genesis_config = GenesisConfig {
|
||||||
accounts,
|
accounts,
|
||||||
epoch_schedule: EpochSchedule::new(slots_per_epoch),
|
epoch_schedule: EpochSchedule::new(slots_per_epoch),
|
||||||
|
operating_mode: OperatingMode::Stable,
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
};
|
};
|
||||||
let mut bank = Arc::new(Bank::new(&genesis_config));
|
let mut bank = Arc::new(Bank::new(&genesis_config));
|
||||||
|
@ -2855,7 +2855,7 @@ pub mod tests {
|
|||||||
let largest_accounts: Vec<RpcAccountBalance> =
|
let largest_accounts: Vec<RpcAccountBalance> =
|
||||||
serde_json::from_value(json["result"]["value"].clone())
|
serde_json::from_value(json["result"]["value"].clone())
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
assert_eq!(largest_accounts.len(), 19);
|
assert_eq!(largest_accounts.len(), 20);
|
||||||
|
|
||||||
// Get Alice balance
|
// Get Alice balance
|
||||||
let req = format!(
|
let req = format!(
|
||||||
@ -2892,7 +2892,7 @@ pub mod tests {
|
|||||||
let largest_accounts: Vec<RpcAccountBalance> =
|
let largest_accounts: Vec<RpcAccountBalance> =
|
||||||
serde_json::from_value(json["result"]["value"].clone())
|
serde_json::from_value(json["result"]["value"].clone())
|
||||||
.expect("actual response deserialization");
|
.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 req = r#"{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts","params":[{"filter":"nonCirculating"}]}"#;
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta);
|
||||||
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
|
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
|
||||||
@ -4853,7 +4853,7 @@ pub mod tests {
|
|||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
let accounts: Vec<RpcKeyedAccount> =
|
let accounts: Vec<RpcKeyedAccount> =
|
||||||
serde_json::from_value(result["result"].clone()).unwrap();
|
serde_json::from_value(result["result"].clone()).unwrap();
|
||||||
assert_eq!(accounts.len(), 3);
|
assert_eq!(accounts.len(), 4);
|
||||||
|
|
||||||
// Test returns only mint accounts
|
// Test returns only mint accounts
|
||||||
let req = format!(
|
let req = format!(
|
||||||
|
@ -385,7 +385,7 @@ mod tests {
|
|||||||
snapshot_utils::SnapshotVersion,
|
snapshot_utils::SnapshotVersion,
|
||||||
};
|
};
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::signature::Signer;
|
use solana_sdk::{genesis_config::OperatingMode, signature::Signer};
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -440,7 +440,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_bank_forks() -> Arc<RwLock<BankForks>> {
|
fn create_bank_forks() -> Arc<RwLock<BankForks>> {
|
||||||
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);
|
let bank = Bank::new(&genesis_config);
|
||||||
Arc::new(RwLock::new(BankForks::new(bank)))
|
Arc::new(RwLock::new(BankForks::new(bank)))
|
||||||
}
|
}
|
||||||
|
10
programs/bpf/Cargo.lock
generated
10
programs/bpf/Cargo.lock
generated
@ -224,6 +224,16 @@ dependencies = [
|
|||||||
"byteorder 1.3.4",
|
"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]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
@ -45,7 +45,9 @@ use solana_sdk::{
|
|||||||
hash::{extend_and_hash, hashv, Hash},
|
hash::{extend_and_hash, hashv, Hash},
|
||||||
incinerator,
|
incinerator,
|
||||||
inflation::Inflation,
|
inflation::Inflation,
|
||||||
native_loader, nonce,
|
native_loader,
|
||||||
|
native_token::sol_to_lamports,
|
||||||
|
nonce,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
sanitize::Sanitize,
|
sanitize::Sanitize,
|
||||||
@ -70,6 +72,29 @@ use std::{
|
|||||||
sync::{Arc, RwLock, RwLockReadGuard},
|
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 SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
|
||||||
|
|
||||||
pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
|
pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
|
||||||
@ -483,6 +508,7 @@ impl Bank {
|
|||||||
new.ancestors.insert(p.slot(), i + 1);
|
new.ancestors.insert(p.slot(), i + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new.reconfigure_token2_native_mint();
|
||||||
new.update_slot_hashes();
|
new.update_slot_hashes();
|
||||||
new.update_rewards(parent.epoch());
|
new.update_rewards(parent.epoch());
|
||||||
new.update_stake_history(Some(parent.epoch()));
|
new.update_stake_history(Some(parent.epoch()));
|
||||||
@ -2334,6 +2360,7 @@ impl Bank {
|
|||||||
for program in builtin_programs.iter() {
|
for program in builtin_programs.iter() {
|
||||||
self.add_builtin_program(&program.name, program.id, program.process_instruction);
|
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) {
|
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)
|
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 {
|
fn fix_recent_blockhashes_sysvar_delay(&self) -> bool {
|
||||||
let activation_slot = match self.operating_mode() {
|
let activation_slot = match self.operating_mode() {
|
||||||
OperatingMode::Development => 0,
|
OperatingMode::Development => 0,
|
||||||
@ -3087,6 +3157,7 @@ mod tests {
|
|||||||
accounts: (0..42)
|
accounts: (0..42)
|
||||||
.map(|_| (Pubkey::new_rand(), Account::new(42, 0, &Pubkey::default())))
|
.map(|_| (Pubkey::new_rand(), Account::new(42, 0, &Pubkey::default())))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
operating_mode: OperatingMode::Stable,
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
}));
|
}));
|
||||||
assert_eq!(bank.capitalization(), 42 * 42);
|
assert_eq!(bank.capitalization(), 42 * 42);
|
||||||
@ -4552,6 +4623,7 @@ mod tests {
|
|||||||
hashes_per_tick: None,
|
hashes_per_tick: None,
|
||||||
target_tick_count: None,
|
target_tick_count: None,
|
||||||
},
|
},
|
||||||
|
operating_mode: OperatingMode::Stable,
|
||||||
|
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
}));
|
}));
|
||||||
@ -4663,6 +4735,7 @@ mod tests {
|
|||||||
hashes_per_tick: None,
|
hashes_per_tick: None,
|
||||||
target_tick_count: None,
|
target_tick_count: None,
|
||||||
},
|
},
|
||||||
|
operating_mode: OperatingMode::Stable,
|
||||||
|
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
}));
|
}));
|
||||||
@ -7653,6 +7726,7 @@ mod tests {
|
|||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
genesis_config.creation_time = 0;
|
genesis_config.creation_time = 0;
|
||||||
|
genesis_config.operating_mode = OperatingMode::Stable;
|
||||||
let mut bank = Arc::new(Bank::new(&genesis_config));
|
let mut bank = Arc::new(Bank::new(&genesis_config));
|
||||||
// Check a few slots, cross an epoch boundary
|
// Check a few slots, cross an epoch boundary
|
||||||
assert_eq!(bank.get_slots_in_epoch(0), 32);
|
assert_eq!(bank.get_slots_in_epoch(0), 32);
|
||||||
@ -7661,25 +7735,25 @@ mod tests {
|
|||||||
if bank.slot == 0 {
|
if bank.slot == 0 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"HsNNxYe9FjPZtW8zNwSrLsB6d8YXoWqhpegE328C5Wvy",
|
"A1pQjC4aGvK5iokQztbwHbeswkCzjkoebkSWc47ctRsK"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if bank.slot == 32 {
|
if bank.slot == 32 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"9rsnmUCTg2wFnKVnaUSEQcSicvPUyXPTmbsakB2o3eTu"
|
"J7NjxvfySQDqMNNJRUcWRvczjEv2TjHgEzJ6seehwPFN"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if bank.slot == 64 {
|
if bank.slot == 64 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"B1JNAeiR89kcqwqeSSQXFN3spcYW2qVJwuu9hQ9dxn1V"
|
"8pfF9QbZxdW1SS51tF5XqjFyMipis5iai6KT2xCKgm66"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if bank.slot == 128 {
|
if bank.slot == 128 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"9iUEmDnWQmjtkoMuR3hJAwQMpCGwHaJAEsfK131rww8y"
|
"9D3YWZ2dpL1fgUo4JMGLfuDzsz64kVqpxiMFmqmGDK5F"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -7770,7 +7844,7 @@ mod tests {
|
|||||||
.map(|_| bank.process_stale_slot_with_budget(0, force_to_return_alive_account))
|
.map(|_| bank.process_stale_slot_with_budget(0, force_to_return_alive_account))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
consumed_budgets.sort();
|
consumed_budgets.sort();
|
||||||
assert_eq!(consumed_budgets, vec![0, 1, 8]);
|
assert_eq!(consumed_budgets, vec![0, 1, 9]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -7864,4 +7938,70 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 496); // no transaction fee charged
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user