genesis config hashmaps (#7107)

This commit is contained in:
Rob Walker 2019-11-26 19:23:37 -08:00 committed by GitHub
parent c706f9b2cd
commit 8d75efdc58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 167 deletions

View File

@ -650,15 +650,5 @@ mod tests {
.sum::<u64>();
assert_eq!(issued_lamports, lamports);
genesis_config
.accounts
.sort_by(|(ka, _), (kb, _)| ka.cmp(kb));
let len = genesis_config.accounts.len();
genesis_config
.accounts
.dedup_by(|(ka, _), (kb, _)| ka == kb);
assert_eq!(genesis_config.accounts.len(), len);
}
}

View File

@ -27,7 +27,15 @@ use solana_sdk::{
use solana_stake_program::stake_state;
use solana_storage_program::storage_contract;
use solana_vote_program::vote_state;
use std::{collections::HashMap, error, fs::File, io, path::PathBuf, str::FromStr, time::Duration};
use std::{
collections::{BTreeMap, HashMap},
error,
fs::File,
io,
path::PathBuf,
str::FromStr,
time::Duration,
};
pub enum AccountFileFormat {
Pubkey,
@ -342,7 +350,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
bootstrap_leader_stake_lamports,
);
let mut accounts = vec![
let mut accounts: BTreeMap<Pubkey, Account> = [
// node needs an account to issue votes from
(
bootstrap_leader_pubkey,
@ -352,13 +360,16 @@ fn main() -> Result<(), Box<dyn error::Error>> {
(bootstrap_vote_pubkey, bootstrap_leader_vote_account),
// bootstrap leader stake
(bootstrap_stake_pubkey, bootstrap_leader_stake_account),
];
]
.iter()
.cloned()
.collect();
if let Some(bootstrap_storage_pubkey) = bootstrap_storage_pubkey {
accounts.push((
accounts.insert(
bootstrap_storage_pubkey,
storage_contract::create_validator_storage_account(bootstrap_leader_pubkey, 1),
));
);
}
let ticks_per_slot = value_t_or_exit!(matches, "ticks_per_slot", u64);
@ -537,27 +548,28 @@ mod tests {
assert_eq!(genesis_config.accounts.len(), genesis_accounts.len());
// Test account data matches
(0..genesis_accounts.len()).for_each(|i| {
for (pubkey_str, b64_account) in genesis_accounts.iter() {
let pubkey = pubkey_str.parse().unwrap();
assert_eq!(
genesis_accounts[&genesis_config.accounts[i].0.to_string()].owner,
genesis_config.accounts[i].1.owner.to_string()
b64_account.owner,
genesis_config.accounts[&pubkey].owner.to_string()
);
assert_eq!(
genesis_accounts[&genesis_config.accounts[i].0.to_string()].balance,
genesis_config.accounts[i].1.lamports
b64_account.balance,
genesis_config.accounts[&pubkey].lamports
);
assert_eq!(
genesis_accounts[&genesis_config.accounts[i].0.to_string()].executable,
genesis_config.accounts[i].1.executable
b64_account.executable,
genesis_config.accounts[&pubkey].executable
);
assert_eq!(
genesis_accounts[&genesis_config.accounts[i].0.to_string()].data,
base64::encode(&genesis_config.accounts[i].1.data)
b64_account.data,
base64::encode(&genesis_config.accounts[&pubkey].data)
);
});
}
}
// Test more accounts can be appended
@ -610,54 +622,37 @@ mod tests {
);
// Test old accounts are still there
(0..genesis_accounts.len()).for_each(|i| {
for (pubkey_str, b64_account) in genesis_accounts.iter() {
let pubkey = &pubkey_str.parse().unwrap();
assert_eq!(
genesis_accounts[&genesis_config.accounts[i].0.to_string()].balance,
genesis_config.accounts[i].1.lamports,
b64_account.balance,
genesis_config.accounts[&pubkey].lamports,
);
});
}
// Test new account data matches
(0..genesis_accounts1.len()).for_each(|i| {
for (pubkey_str, b64_account) in genesis_accounts1.iter() {
let pubkey = pubkey_str.parse().unwrap();
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.owner,
genesis_config.accounts[genesis_accounts.len() + i]
.1
.owner
.to_string(),
b64_account.owner,
genesis_config.accounts[&pubkey].owner.to_string()
);
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.balance,
genesis_config.accounts[genesis_accounts.len() + i]
.1
.lamports,
b64_account.balance,
genesis_config.accounts[&pubkey].lamports,
);
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.executable,
genesis_config.accounts[genesis_accounts.len() + i]
.1
.executable,
b64_account.executable,
genesis_config.accounts[&pubkey].executable,
);
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.data,
base64::encode(&genesis_config.accounts[genesis_accounts.len() + i].1.data),
b64_account.data,
base64::encode(&genesis_config.accounts[&pubkey].data),
);
});
}
// Test accounts from keypairs can be appended
let account_keypairs: Vec<_> = (0..3).map(|_| Keypair::new()).collect();
@ -712,89 +707,60 @@ mod tests {
);
// Test old accounts are still there
(0..genesis_accounts.len()).for_each(|i| {
for (pubkey_str, b64_account) in genesis_accounts {
let pubkey = pubkey_str.parse().unwrap();
assert_eq!(
genesis_accounts[&genesis_config.accounts[i].0.to_string()].balance,
genesis_config.accounts[i].1.lamports,
b64_account.balance,
genesis_config.accounts[&pubkey].lamports,
);
});
}
// Test new account data matches
(0..genesis_accounts1.len()).for_each(|i| {
for (pubkey_str, b64_account) in genesis_accounts1 {
let pubkey = pubkey_str.parse().unwrap();
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.owner,
genesis_config.accounts[genesis_accounts.len() + i]
.1
.owner
.to_string(),
b64_account.owner,
genesis_config.accounts[&pubkey].owner.to_string(),
);
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.balance,
genesis_config.accounts[genesis_accounts.len() + i]
.1
.lamports,
b64_account.balance,
genesis_config.accounts[&pubkey].lamports,
);
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.executable,
genesis_config.accounts[genesis_accounts.len() + i]
.1
.executable,
b64_account.executable,
genesis_config.accounts[&pubkey].executable,
);
assert_eq!(
genesis_accounts1[&genesis_config.accounts[genesis_accounts.len() + i]
.0
.to_string()]
.data,
base64::encode(&genesis_config.accounts[genesis_accounts.len() + i].1.data),
b64_account.data,
base64::encode(&genesis_config.accounts[&pubkey].data),
);
});
}
let offset = genesis_accounts.len() + genesis_accounts1.len();
// Test account data for keypairs matches
account_keypairs.iter().for_each(|keypair| {
let mut i = 0;
(offset..(offset + account_keypairs.len())).for_each(|n| {
if keypair.pubkey() == genesis_config.accounts[n].0 {
i = n;
}
});
assert_ne!(i, 0);
let keypair_str = serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap();
let pubkey = keypair.pubkey();
assert_eq!(
genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.owner,
genesis_config.accounts[i].1.owner.to_string(),
genesis_accounts2[&keypair_str].owner,
genesis_config.accounts[&pubkey].owner.to_string(),
);
assert_eq!(
genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.balance,
genesis_config.accounts[i].1.lamports,
genesis_accounts2[&keypair_str].balance,
genesis_config.accounts[&pubkey].lamports,
);
assert_eq!(
genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.executable,
genesis_config.accounts[i].1.executable,
genesis_accounts2[&keypair_str].executable,
genesis_config.accounts[&pubkey].executable,
);
assert_eq!(
genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.data,
base64::encode(&genesis_config.accounts[i].1.data),
genesis_accounts2[&keypair_str].data,
base64::encode(&genesis_config.accounts[&pubkey].data),
);
});
}

View File

@ -21,17 +21,16 @@ pub struct StakerInfo {
}
// lamports required to run staking operations for one year
// the staker account needs to be rent exempt *and* carry enough
// the staker account needs carry enough
// lamports to cover TX fees (delegation) for one year,
// and we support one delegation per epoch
fn calculate_staker_lamports(genesis_config: &GenesisConfig) -> u64 {
genesis_config.rent.minimum_balance(0).max(1)
+ genesis_config.fee_calculator.max_lamports_per_signature
* genesis_config.epoch_schedule.get_epoch(years_as_slots(
1.0,
&genesis_config.poh_config.target_tick_duration,
genesis_config.ticks_per_slot,
) as Slot)
fn calculate_staker_fees(genesis_config: &GenesisConfig, years: f64) -> u64 {
genesis_config.fee_calculator.max_lamports_per_signature
* genesis_config.epoch_schedule.get_epoch(years_as_slots(
years,
&genesis_config.poh_config.target_tick_duration,
genesis_config.ticks_per_slot,
) as Slot)
}
/// create stake accounts for lamports with at most stake_granularity in each
@ -53,19 +52,23 @@ pub fn create_and_add_stakes(
let total_lamports = sol_to_lamports(staker_info.sol);
let staker_lamports = calculate_staker_lamports(genesis_config);
let staker_account = (
authorized.staker,
Account::new(staker_lamports, 0, &system_program::id()),
);
let staker_rent_reserve = get_stake_rent_exempt_reserve(&genesis_config.rent).max(1);
let staker_fees = calculate_staker_fees(genesis_config, 1.0);
let stakes_lamports = if !genesis_config.accounts.contains(&staker_account) {
genesis_config.accounts.push(staker_account);
let mut stakes_lamports = total_lamports - staker_fees;
total_lamports - staker_lamports
} else {
total_lamports
};
// lamports required to run staking operations for one year
// the staker account needs to be rent exempt *and* carry enough
// lamports to cover TX fees (delegation) for one year,
// and we support one delegation per epoch
genesis_config
.accounts
.entry(authorized.staker)
.or_insert_with(|| {
stakes_lamports -= staker_rent_reserve;
Account::new(staker_rent_reserve, 0, &system_program::id())
})
.lamports += staker_fees;
// the staker account needs to be rent exempt *and* carry enough
// lamports to cover TX fees (delegation) for one year
@ -150,11 +153,10 @@ mod tests {
granularity: u64,
len: usize,
) {
assert!(
total_lamports
== create_and_add_stakes(genesis_config, staker_info, unlock_info, granularity)
assert_eq!(
total_lamports,
create_and_add_stakes(genesis_config, staker_info, unlock_info, granularity)
);
assert_eq!(genesis_config.accounts.len(), len);
assert_eq!(
genesis_config
@ -169,7 +171,7 @@ mod tests {
.iter()
.all(|(_pubkey, account)| account.lamports <= granularity
|| account.lamports - granularity
< get_stake_rent_exempt_reserve(&genesis_config.rent)));
<= get_stake_rent_exempt_reserve(&genesis_config.rent)));
}
#[test]
@ -236,9 +238,34 @@ mod tests {
2 + 1,
);
// exactly reserve as a remainder
// exactly reserve as a remainder, reserve gets folded in
let granularity = reserve * 3;
let total_lamports = reserve + (granularity + reserve) * 2;
create_and_check_stakes(
&mut GenesisConfig {
rent,
..GenesisConfig::default()
},
&StakerInfo {
name: "fun",
staker: "cafebabedeadbeef000000000000000000000000000000000000000000000000",
withdrawer: "cafebabedeadbeef000000000000000000000000000000000000000000000000",
sol: lamports_to_sol(total_lamports),
custodian: "0000000000000000000000000000000000000000000000000000000000000000",
},
&UnlockInfo {
cliff_fraction: 0.5,
cliff_years: 0.5,
unlocks: 1,
unlock_years: 0.5,
},
total_lamports,
granularity,
2 + 1,
);
// exactly reserve + 1 as a remainder, reserve + 1 gets its own stake
let granularity = reserve * 3;
let total_lamports = reserve + (granularity + reserve + 1) * 2;
create_and_check_stakes(
&mut GenesisConfig {
rent,

View File

@ -151,7 +151,10 @@ impl LocalCluster {
match genesis_config.operating_mode {
OperatingMode::SoftLaunch => {
genesis_config.native_instruction_processors =
solana_genesis_programs::get_programs(genesis_config.operating_mode, 0).unwrap()
solana_genesis_programs::get_programs(genesis_config.operating_mode, 0)
.unwrap()
.into_iter()
.collect()
}
// create_genesis_config_with_leader() assumes OperatingMode::Development so do
// nothing...
@ -169,18 +172,13 @@ impl LocalCluster {
.push(solana_storage_program!());
let storage_keypair = Keypair::new();
genesis_config.accounts.push((
genesis_config.add_account(
storage_keypair.pubkey(),
storage_contract::create_validator_storage_account(leader_pubkey, 1),
));
);
// Replace staking config
genesis_config.accounts = genesis_config
.accounts
.into_iter()
.filter(|(pubkey, _)| *pubkey != stake_config::id())
.collect();
genesis_config.accounts.push((
genesis_config.add_account(
stake_config::id(),
stake_config::create_account(
1,
@ -189,7 +187,7 @@ impl LocalCluster {
slash_penalty: std::u8::MAX,
},
),
));
);
let (leader_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config);
let leader_contact_info = leader_node.info.clone();

View File

@ -45,12 +45,7 @@ mod tests {
add_genesis_accounts(&mut genesis_config);
for _i in 0..NUM_REWARDS_POOLS {
let id = random_id();
assert!(genesis_config
.rewards_pools
.iter()
.position(|x| x.0 == id)
.is_some());
assert!(genesis_config.rewards_pools.get(&random_id()).is_some())
}
}
}

View File

@ -49,7 +49,7 @@ pub fn create_genesis_config_with_leader(
bootstrap_leader_stake_lamports,
);
let accounts = vec![
let accounts = [
(
mint_keypair.pubkey(),
Account::new(mint_lamports, 0, &system_program::id()),
@ -66,7 +66,10 @@ pub fn create_genesis_config_with_leader(
bootstrap_leader_staking_keypair.pubkey(),
bootstrap_leader_stake_account,
),
];
]
.iter()
.cloned()
.collect();
// Bare minimum program set
let native_instruction_processors = vec![

View File

@ -16,6 +16,7 @@ use crate::{
use bincode::{deserialize, serialize};
use memmap::Mmap;
use std::{
collections::BTreeMap,
fs::{File, OpenOptions},
io::Write,
path::{Path, PathBuf},
@ -29,9 +30,9 @@ pub enum OperatingMode {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GenesisConfig {
pub accounts: Vec<(Pubkey, Account)>,
pub accounts: BTreeMap<Pubkey, Account>,
pub native_instruction_processors: Vec<(String, Pubkey)>,
pub rewards_pools: Vec<(Pubkey, Account)>,
pub rewards_pools: BTreeMap<Pubkey, Account>,
pub ticks_per_slot: u64,
pub slots_per_segment: u64,
pub poh_config: PohConfig,
@ -60,9 +61,9 @@ pub fn create_genesis_config(lamports: u64) -> (GenesisConfig, Keypair) {
impl Default for GenesisConfig {
fn default() -> Self {
Self {
accounts: Vec::new(),
native_instruction_processors: Vec::new(),
rewards_pools: Vec::new(),
accounts: BTreeMap::default(),
native_instruction_processors: Vec::default(),
rewards_pools: BTreeMap::default(),
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
slots_per_segment: DEFAULT_SLOTS_PER_SEGMENT,
poh_config: PohConfig::default(),
@ -81,15 +82,18 @@ impl GenesisConfig {
native_instruction_processors: &[(String, Pubkey)],
) -> Self {
Self {
accounts: accounts.to_vec(),
accounts: accounts
.iter()
.cloned()
.collect::<BTreeMap<Pubkey, Account>>(),
native_instruction_processors: native_instruction_processors.to_vec(),
..GenesisConfig::default()
}
}
pub fn hash(&self) -> Hash {
let serialized = serde_json::to_string(self).unwrap();
hash(&serialized.into_bytes())
let serialized = serialize(&self).unwrap();
hash(&serialized)
}
fn genesis_filename(ledger_path: &Path) -> PathBuf {
@ -140,7 +144,7 @@ impl GenesisConfig {
}
pub fn add_account(&mut self, pubkey: Pubkey, account: Account) {
self.accounts.push((pubkey, account));
self.accounts.insert(pubkey, account);
}
pub fn add_native_instruction_processor(&mut self, name: String, program_id: Pubkey) {
@ -148,7 +152,7 @@ impl GenesisConfig {
}
pub fn add_rewards_pool(&mut self, pubkey: Pubkey, account: Account) {
self.rewards_pools.push((pubkey, account));
self.rewards_pools.insert(pubkey, account);
}
}