Boot the Builder pattern from GenesisBlock (#6364)

This commit is contained in:
Greg Fitzgerald 2019-10-15 13:52:44 -06:00 committed by GitHub
parent 41067de5e4
commit ae41c88eb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 216 additions and 273 deletions

3
Cargo.lock generated
View File

@ -3423,9 +3423,7 @@ name = "solana-genesis"
version = "0.20.0" version = "0.20.0"
dependencies = [ dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3436,7 +3434,6 @@ dependencies = [
"solana-stake-api 0.20.0", "solana-stake-api 0.20.0",
"solana-storage-api 0.20.0", "solana-storage-api 0.20.0",
"solana-vote-api 0.20.0", "solana-vote-api 0.20.0",
"sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -11,7 +11,7 @@ use solana_drone::drone::request_airdrop_transaction;
use solana_exchange_api::exchange_instruction; use solana_exchange_api::exchange_instruction;
use solana_exchange_api::exchange_state::*; use solana_exchange_api::exchange_state::*;
use solana_exchange_api::id; use solana_exchange_api::id;
use solana_genesis::PrimordialAccountDetails; use solana_genesis::Base64Account;
use solana_metrics::datapoint_info; use solana_metrics::datapoint_info;
use solana_sdk::client::Client; use solana_sdk::client::Client;
use solana_sdk::client::SyncClient; use solana_sdk::client::SyncClient;
@ -89,7 +89,7 @@ pub fn create_client_accounts_file(
keypairs.iter().for_each(|keypair| { keypairs.iter().for_each(|keypair| {
accounts.insert( accounts.insert(
serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(), serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(),
PrimordialAccountDetails { Base64Account {
balance: fund_amount, balance: fund_amount,
executable: false, executable: false,
owner: system_program::id().to_string(), owner: system_program::id().to_string(),
@ -140,8 +140,7 @@ where
let path = Path::new(&client_ids_and_stake_file); let path = Path::new(&client_ids_and_stake_file);
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
let accounts: HashMap<String, PrimordialAccountDetails> = let accounts: HashMap<String, Base64Account> = serde_yaml::from_reader(file).unwrap();
serde_yaml::from_reader(file).unwrap();
accounts accounts
.into_iter() .into_iter()
.map(|(keypair, _)| { .map(|(keypair, _)| {

View File

@ -2,7 +2,7 @@ use log::*;
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs}; use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs};
use solana_bench_tps::cli; use solana_bench_tps::cli;
use solana_core::gossip_service::{discover_cluster, get_multi_client}; use solana_core::gossip_service::{discover_cluster, get_multi_client};
use solana_genesis::PrimordialAccountDetails; use solana_genesis::Base64Account;
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_program; use solana_sdk::system_program;
@ -46,7 +46,7 @@ fn main() {
keypairs.iter().for_each(|keypair| { keypairs.iter().for_each(|keypair| {
accounts.insert( accounts.insert(
serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(), serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(),
PrimordialAccountDetails { Base64Account {
balance: num_lamports_per_account, balance: num_lamports_per_account,
executable: false, executable: false,
owner: system_program::id().to_string(), owner: system_program::id().to_string(),
@ -85,8 +85,7 @@ fn main() {
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
info!("Reading {}", client_ids_and_stake_file); info!("Reading {}", client_ids_and_stake_file);
let accounts: HashMap<String, PrimordialAccountDetails> = let accounts: HashMap<String, Base64Account> = serde_yaml::from_reader(file).unwrap();
serde_yaml::from_reader(file).unwrap();
let mut keypairs = vec![]; let mut keypairs = vec![];
let mut last_balance = 0; let mut last_balance = 0;

View File

@ -10,7 +10,6 @@ homepage = "https://solana.com/"
[dependencies] [dependencies]
base64 = "0.10.1" base64 = "0.10.1"
bincode = "1.2.0"
clap = "2.33.0" clap = "2.33.0"
serde = "1.0.101" serde = "1.0.101"
serde_derive = "1.0.101" serde_derive = "1.0.101"
@ -23,5 +22,3 @@ solana-stake-api = { path = "../programs/stake_api", version = "0.20.0" }
solana-storage-api = { path = "../programs/storage_api", version = "0.20.0" } solana-storage-api = { path = "../programs/storage_api", version = "0.20.0" }
solana-vote-api = { path = "../programs/vote_api", version = "0.20.0" } solana-vote-api = { path = "../programs/vote_api", version = "0.20.0" }
tempfile = "3.1.0" tempfile = "3.1.0"
sys-info = "0.5.8"
rayon = "1.2.0"

View File

@ -1,7 +1,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// An account where the data is encoded as a Base64 string.
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct PrimordialAccountDetails { pub struct Base64Account {
pub balance: u64, pub balance: u64,
pub owner: String, pub owner: String,
pub data: String, pub data: String,

View File

@ -1,16 +1,15 @@
//! A command-line executable for generating the chain's genesis block. //! A command-line executable for generating the chain's genesis block.
use base64;
use clap::{crate_description, crate_name, crate_version, value_t_or_exit, App, Arg}; use clap::{crate_description, crate_name, crate_version, value_t_or_exit, App, Arg};
use solana_core::blocktree::create_new_ledger; use solana_core::blocktree::create_new_ledger;
use solana_core::poh::compute_hashes_per_tick; use solana_core::poh::compute_hashes_per_tick;
use solana_genesis::PrimordialAccountDetails; use solana_genesis::Base64Account;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
clock, clock,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::FeeCalculator,
genesis_block::Builder, genesis_block::GenesisBlock,
poh_config::PohConfig, poh_config::PohConfig,
pubkey::Pubkey, pubkey::Pubkey,
rent_calculator::RentCalculator, rent_calculator::RentCalculator,
@ -29,18 +28,18 @@ pub enum AccountFileFormat {
Keypair, Keypair,
} }
pub fn append_primordial_accounts( pub fn add_genesis_accounts(
file: &str, file: &str,
file_format: AccountFileFormat, file_format: AccountFileFormat,
mut builder: Builder, genesis_block: &mut GenesisBlock,
) -> io::Result<(Builder)> { ) -> io::Result<()> {
let accounts_file = File::open(file.to_string())?; let accounts_file = File::open(file.to_string())?;
let primordial_accounts: HashMap<String, PrimordialAccountDetails> = let genesis_accounts: HashMap<String, Base64Account> =
serde_yaml::from_reader(accounts_file) serde_yaml::from_reader(accounts_file)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?; .map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
for (account, account_details) in primordial_accounts { for (account, account_details) in genesis_accounts {
let pubkey = match file_format { let pubkey = match file_format {
AccountFileFormat::Pubkey => Pubkey::from_str(account.as_str()).map_err(|err| { AccountFileFormat::Pubkey => Pubkey::from_str(account.as_str()).map_err(|err| {
io::Error::new( io::Error::new(
@ -72,10 +71,10 @@ pub fn append_primordial_accounts(
} }
account.executable = account_details.executable; account.executable = account_details.executable;
builder = builder.account(pubkey, account); genesis_block.add_account(pubkey, account);
} }
Ok(builder) Ok(())
} }
fn main() -> Result<(), Box<dyn error::Error>> { fn main() -> Result<(), Box<dyn error::Error>> {
@ -317,8 +316,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
bootstrap_leader_stake_lamports, bootstrap_leader_stake_lamports,
); );
let mut builder = Builder::new() let accounts = vec![
.accounts(&[
// the mint // the mint
( (
mint_keypair.pubkey(), mint_keypair.pubkey(),
@ -340,27 +338,22 @@ fn main() -> Result<(), Box<dyn error::Error>> {
1, 1,
), ),
), ),
]) ];
.native_instruction_processors(&solana_genesis_programs::get())
.ticks_per_slot(value_t_or_exit!(matches, "ticks_per_slot", u64));
let ticks_per_slot = value_t_or_exit!(matches, "ticks_per_slot", u64);
let slots_per_epoch = value_t_or_exit!(matches, "slots_per_epoch", u64); let slots_per_epoch = value_t_or_exit!(matches, "slots_per_epoch", u64);
let epoch_schedule = EpochSchedule::new(slots_per_epoch); let epoch_schedule = EpochSchedule::new(slots_per_epoch);
builder = builder.epoch_schedule(epoch_schedule);
let fee_calculator = FeeCalculator::new( let fee_calculator = FeeCalculator::new(
value_t_or_exit!(matches, "target_lamports_per_signature", u64), value_t_or_exit!(matches, "target_lamports_per_signature", u64),
value_t_or_exit!(matches, "target_signatures_per_slot", usize), value_t_or_exit!(matches, "target_signatures_per_slot", usize),
); );
builder = builder.fee_calculator(fee_calculator);
let rent_calculator = RentCalculator { let rent_calculator = RentCalculator {
lamports_per_byte_year: value_t_or_exit!(matches, "lamports_per_byte_year", u64), lamports_per_byte_year: value_t_or_exit!(matches, "lamports_per_byte_year", u64),
exemption_threshold: value_t_or_exit!(matches, "rent_exemption_threshold", f64), exemption_threshold: value_t_or_exit!(matches, "rent_exemption_threshold", f64),
burn_percent: value_t_or_exit!(matches, "rent_burn_percentage", u8), burn_percent: value_t_or_exit!(matches, "rent_burn_percentage", u8),
}; };
builder = builder.rent_calculator(rent_calculator);
let mut poh_config = PohConfig::default(); let mut poh_config = PohConfig::default();
poh_config.target_tick_duration = poh_config.target_tick_duration =
@ -380,28 +373,38 @@ fn main() -> Result<(), Box<dyn error::Error>> {
poh_config.hashes_per_tick = Some(value_t_or_exit!(matches, "hashes_per_tick", u64)); poh_config.hashes_per_tick = Some(value_t_or_exit!(matches, "hashes_per_tick", u64));
} }
} }
builder = builder.poh_config(poh_config);
let mut genesis_block = GenesisBlock {
accounts,
native_instruction_processors: solana_genesis_programs::get(),
ticks_per_slot,
epoch_schedule,
fee_calculator,
rent_calculator,
poh_config,
..GenesisBlock::default()
};
if let Some(file) = matches.value_of("primordial_accounts_file") { if let Some(file) = matches.value_of("primordial_accounts_file") {
builder = append_primordial_accounts(file, AccountFileFormat::Pubkey, builder)?; add_genesis_accounts(file, AccountFileFormat::Pubkey, &mut genesis_block)?;
} }
if let Some(file) = matches.value_of("primordial_keypairs_file") { if let Some(file) = matches.value_of("primordial_keypairs_file") {
builder = append_primordial_accounts(file, AccountFileFormat::Keypair, builder)?; add_genesis_accounts(file, AccountFileFormat::Keypair, &mut genesis_block)?;
} }
// add genesis stuff from storage and stake // add genesis stuff from storage and stake
builder = solana_storage_api::rewards_pools::genesis(builder); solana_storage_api::rewards_pools::add_genesis_accounts(&mut genesis_block);
builder = solana_stake_api::genesis(builder); solana_stake_api::add_genesis_accounts(&mut genesis_block);
create_new_ledger(&ledger_path, &builder.build())?; create_new_ledger(&ledger_path, &genesis_block)?;
Ok(()) Ok(())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use solana_sdk::genesis_block::Builder; use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::remove_file; use std::fs::remove_file;
@ -412,37 +415,37 @@ mod tests {
#[test] #[test]
fn test_append_primordial_accounts_to_genesis() { fn test_append_primordial_accounts_to_genesis() {
// Test invalid file returns error // Test invalid file returns error
assert!(append_primordial_accounts( assert!(add_genesis_accounts(
"unknownfile", "unknownfile",
AccountFileFormat::Pubkey, AccountFileFormat::Pubkey,
Builder::new() &mut GenesisBlock::default()
) )
.is_err()); .is_err());
let mut builder = Builder::new(); let mut genesis_block = GenesisBlock::default();
let mut primordial_accounts = HashMap::new(); let mut genesis_accounts = HashMap::new();
primordial_accounts.insert( genesis_accounts.insert(
Pubkey::new_rand().to_string(), Pubkey::new_rand().to_string(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 2 as u64, balance: 2 as u64,
executable: false, executable: false,
data: String::from("aGVsbG8="), data: String::from("aGVsbG8="),
}, },
); );
primordial_accounts.insert( genesis_accounts.insert(
Pubkey::new_rand().to_string(), Pubkey::new_rand().to_string(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 1 as u64, balance: 1 as u64,
executable: true, executable: true,
data: String::from("aGVsbG8gd29ybGQ="), data: String::from("aGVsbG8gd29ybGQ="),
}, },
); );
primordial_accounts.insert( genesis_accounts.insert(
Pubkey::new_rand().to_string(), Pubkey::new_rand().to_string(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 3 as u64, balance: 3 as u64,
executable: true, executable: true,
@ -450,15 +453,15 @@ mod tests {
}, },
); );
let serialized = serde_yaml::to_string(&primordial_accounts).unwrap(); let serialized = serde_yaml::to_string(&genesis_accounts).unwrap();
let path = Path::new("test_append_primordial_accounts_to_genesis.yml"); let path = Path::new("test_append_primordial_accounts_to_genesis.yml");
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
file.write_all(&serialized.into_bytes()).unwrap(); file.write_all(&serialized.into_bytes()).unwrap();
builder = append_primordial_accounts( add_genesis_accounts(
"test_append_primordial_accounts_to_genesis.yml", "test_append_primordial_accounts_to_genesis.yml",
AccountFileFormat::Pubkey, AccountFileFormat::Pubkey,
builder, &mut genesis_block,
) )
.expect("test_append_primordial_accounts_to_genesis.yml"); .expect("test_append_primordial_accounts_to_genesis.yml");
// Test valid file returns ok // Test valid file returns ok
@ -466,57 +469,56 @@ mod tests {
remove_file(path).unwrap(); remove_file(path).unwrap();
{ {
let genesis_block = builder.clone().build();
// Test all accounts were added // Test all accounts were added
assert_eq!(genesis_block.accounts.len(), primordial_accounts.len()); assert_eq!(genesis_block.accounts.len(), genesis_accounts.len());
// Test account data matches // Test account data matches
(0..primordial_accounts.len()).for_each(|i| { (0..genesis_accounts.len()).for_each(|i| {
assert_eq!( assert_eq!(
primordial_accounts[&genesis_block.accounts[i].0.to_string()].owner, genesis_accounts[&genesis_block.accounts[i].0.to_string()].owner,
genesis_block.accounts[i].1.owner.to_string() genesis_block.accounts[i].1.owner.to_string()
); );
assert_eq!( assert_eq!(
primordial_accounts[&genesis_block.accounts[i].0.to_string()].balance, genesis_accounts[&genesis_block.accounts[i].0.to_string()].balance,
genesis_block.accounts[i].1.lamports genesis_block.accounts[i].1.lamports
); );
assert_eq!( assert_eq!(
primordial_accounts[&genesis_block.accounts[i].0.to_string()].executable, genesis_accounts[&genesis_block.accounts[i].0.to_string()].executable,
genesis_block.accounts[i].1.executable genesis_block.accounts[i].1.executable
); );
assert_eq!( assert_eq!(
primordial_accounts[&genesis_block.accounts[i].0.to_string()].data, genesis_accounts[&genesis_block.accounts[i].0.to_string()].data,
base64::encode(&genesis_block.accounts[i].1.data) base64::encode(&genesis_block.accounts[i].1.data)
); );
}); });
} }
// Test more accounts can be appended // Test more accounts can be appended
let mut primordial_accounts1 = HashMap::new(); let mut genesis_accounts1 = HashMap::new();
primordial_accounts1.insert( genesis_accounts1.insert(
Pubkey::new_rand().to_string(), Pubkey::new_rand().to_string(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 6 as u64, balance: 6 as u64,
executable: true, executable: true,
data: String::from("eW91IGFyZQ=="), data: String::from("eW91IGFyZQ=="),
}, },
); );
primordial_accounts1.insert( genesis_accounts1.insert(
Pubkey::new_rand().to_string(), Pubkey::new_rand().to_string(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 5 as u64, balance: 5 as u64,
executable: false, executable: false,
data: String::from("bWV0YSBzdHJpbmc="), data: String::from("bWV0YSBzdHJpbmc="),
}, },
); );
primordial_accounts1.insert( genesis_accounts1.insert(
Pubkey::new_rand().to_string(), Pubkey::new_rand().to_string(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 10 as u64, balance: 10 as u64,
executable: false, executable: false,
@ -524,101 +526,100 @@ mod tests {
}, },
); );
let serialized = serde_yaml::to_string(&primordial_accounts1).unwrap(); let serialized = serde_yaml::to_string(&genesis_accounts1).unwrap();
let path = Path::new("test_append_primordial_accounts_to_genesis.yml"); let path = Path::new("test_append_primordial_accounts_to_genesis.yml");
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
file.write_all(&serialized.into_bytes()).unwrap(); file.write_all(&serialized.into_bytes()).unwrap();
builder = append_primordial_accounts( add_genesis_accounts(
"test_append_primordial_accounts_to_genesis.yml", "test_append_primordial_accounts_to_genesis.yml",
AccountFileFormat::Pubkey, AccountFileFormat::Pubkey,
builder, &mut genesis_block,
) )
.expect("test_append_primordial_accounts_to_genesis.yml"); .expect("test_append_primordial_accounts_to_genesis.yml");
remove_file(path).unwrap(); remove_file(path).unwrap();
let genesis_block = builder.clone().build();
// Test total number of accounts is correct // Test total number of accounts is correct
assert_eq!( assert_eq!(
genesis_block.accounts.len(), genesis_block.accounts.len(),
primordial_accounts.len() + primordial_accounts1.len() genesis_accounts.len() + genesis_accounts1.len()
); );
// Test old accounts are still there // Test old accounts are still there
(0..primordial_accounts.len()).for_each(|i| { (0..genesis_accounts.len()).for_each(|i| {
assert_eq!( assert_eq!(
primordial_accounts[&genesis_block.accounts[i].0.to_string()].balance, genesis_accounts[&genesis_block.accounts[i].0.to_string()].balance,
genesis_block.accounts[i].1.lamports, genesis_block.accounts[i].1.lamports,
); );
}); });
// Test new account data matches // Test new account data matches
(0..primordial_accounts1.len()).for_each(|i| { (0..genesis_accounts1.len()).for_each(|i| {
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.owner, .owner,
genesis_block.accounts[primordial_accounts.len() + i] genesis_block.accounts[genesis_accounts.len() + i]
.1 .1
.owner .owner
.to_string(), .to_string(),
); );
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.balance, .balance,
genesis_block.accounts[primordial_accounts.len() + i] genesis_block.accounts[genesis_accounts.len() + i]
.1 .1
.lamports, .lamports,
); );
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.executable, .executable,
genesis_block.accounts[primordial_accounts.len() + i] genesis_block.accounts[genesis_accounts.len() + i]
.1 .1
.executable, .executable,
); );
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.data, .data,
base64::encode(&genesis_block.accounts[primordial_accounts.len() + i].1.data), base64::encode(&genesis_block.accounts[genesis_accounts.len() + i].1.data),
); );
}); });
// Test accounts from keypairs can be appended // Test accounts from keypairs can be appended
let account_keypairs: Vec<_> = (0..3).map(|_| Keypair::new()).collect(); let account_keypairs: Vec<_> = (0..3).map(|_| Keypair::new()).collect();
let mut primordial_accounts2 = HashMap::new(); let mut genesis_accounts2 = HashMap::new();
primordial_accounts2.insert( genesis_accounts2.insert(
serde_json::to_string(&account_keypairs[0].to_bytes().to_vec()).unwrap(), serde_json::to_string(&account_keypairs[0].to_bytes().to_vec()).unwrap(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 20 as u64, balance: 20 as u64,
executable: true, executable: true,
data: String::from("Y2F0IGRvZw=="), data: String::from("Y2F0IGRvZw=="),
}, },
); );
primordial_accounts2.insert( genesis_accounts2.insert(
serde_json::to_string(&account_keypairs[1].to_bytes().to_vec()).unwrap(), serde_json::to_string(&account_keypairs[1].to_bytes().to_vec()).unwrap(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 15 as u64, balance: 15 as u64,
executable: false, executable: false,
data: String::from("bW9ua2V5IGVsZXBoYW50"), data: String::from("bW9ua2V5IGVsZXBoYW50"),
}, },
); );
primordial_accounts2.insert( genesis_accounts2.insert(
serde_json::to_string(&account_keypairs[2].to_bytes().to_vec()).unwrap(), serde_json::to_string(&account_keypairs[2].to_bytes().to_vec()).unwrap(),
PrimordialAccountDetails { Base64Account {
owner: Pubkey::new_rand().to_string(), owner: Pubkey::new_rand().to_string(),
balance: 30 as u64, balance: 30 as u64,
executable: true, executable: true,
@ -626,80 +627,79 @@ mod tests {
}, },
); );
let serialized = serde_yaml::to_string(&primordial_accounts2).unwrap(); let serialized = serde_yaml::to_string(&genesis_accounts2).unwrap();
let path = Path::new("test_append_primordial_accounts_to_genesis.yml"); let path = Path::new("test_append_primordial_accounts_to_genesis.yml");
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
file.write_all(&serialized.into_bytes()).unwrap(); file.write_all(&serialized.into_bytes()).unwrap();
builder = append_primordial_accounts( add_genesis_accounts(
"test_append_primordial_accounts_to_genesis.yml", "test_append_primordial_accounts_to_genesis.yml",
AccountFileFormat::Keypair, AccountFileFormat::Keypair,
builder, &mut genesis_block,
) )
.expect("builder"); .expect("genesis");
builder = solana_storage_api::rewards_pools::genesis(builder); solana_storage_api::rewards_pools::add_genesis_accounts(&mut genesis_block);
remove_file(path).unwrap(); remove_file(path).unwrap();
let genesis_block = builder.clone().build();
// Test total number of accounts is correct // Test total number of accounts is correct
assert_eq!( assert_eq!(
genesis_block.accounts.len(), genesis_block.accounts.len(),
primordial_accounts.len() + primordial_accounts1.len() + primordial_accounts2.len() genesis_accounts.len() + genesis_accounts1.len() + genesis_accounts2.len()
); );
// Test old accounts are still there // Test old accounts are still there
(0..primordial_accounts.len()).for_each(|i| { (0..genesis_accounts.len()).for_each(|i| {
assert_eq!( assert_eq!(
primordial_accounts[&genesis_block.accounts[i].0.to_string()].balance, genesis_accounts[&genesis_block.accounts[i].0.to_string()].balance,
genesis_block.accounts[i].1.lamports, genesis_block.accounts[i].1.lamports,
); );
}); });
// Test new account data matches // Test new account data matches
(0..primordial_accounts1.len()).for_each(|i| { (0..genesis_accounts1.len()).for_each(|i| {
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.owner, .owner,
genesis_block.accounts[primordial_accounts.len() + i] genesis_block.accounts[genesis_accounts.len() + i]
.1 .1
.owner .owner
.to_string(), .to_string(),
); );
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.balance, .balance,
genesis_block.accounts[primordial_accounts.len() + i] genesis_block.accounts[genesis_accounts.len() + i]
.1 .1
.lamports, .lamports,
); );
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.executable, .executable,
genesis_block.accounts[primordial_accounts.len() + i] genesis_block.accounts[genesis_accounts.len() + i]
.1 .1
.executable, .executable,
); );
assert_eq!( assert_eq!(
primordial_accounts1[&genesis_block.accounts[primordial_accounts.len() + i] genesis_accounts1[&genesis_block.accounts[genesis_accounts.len() + i]
.0 .0
.to_string()] .to_string()]
.data, .data,
base64::encode(&genesis_block.accounts[primordial_accounts.len() + i].1.data), base64::encode(&genesis_block.accounts[genesis_accounts.len() + i].1.data),
); );
}); });
let offset = primordial_accounts.len() + primordial_accounts1.len(); let offset = genesis_accounts.len() + genesis_accounts1.len();
// Test account data for keypairs matches // Test account data for keypairs matches
account_keypairs.iter().for_each(|keypair| { account_keypairs.iter().for_each(|keypair| {
let mut i = 0; let mut i = 0;
@ -712,25 +712,25 @@ mod tests {
assert_ne!(i, 0); assert_ne!(i, 0);
assert_eq!( assert_eq!(
primordial_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()] genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.owner, .owner,
genesis_block.accounts[i].1.owner.to_string(), genesis_block.accounts[i].1.owner.to_string(),
); );
assert_eq!( assert_eq!(
primordial_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()] genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.balance, .balance,
genesis_block.accounts[i].1.lamports, genesis_block.accounts[i].1.lamports,
); );
assert_eq!( assert_eq!(
primordial_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()] genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.executable, .executable,
genesis_block.accounts[i].1.executable, genesis_block.accounts[i].1.executable,
); );
assert_eq!( assert_eq!(
primordial_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()] genesis_accounts2[&serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap()]
.data, .data,
base64::encode(&genesis_block.accounts[i].1.data), base64::encode(&genesis_block.accounts[i].1.data),
); );
@ -738,7 +738,7 @@ mod tests {
} }
#[test] #[test]
fn test_primordial_account_struct_compatibility() { fn test_genesis_account_struct_compatibility() {
let yaml_string_pubkey = "--- let yaml_string_pubkey = "---
98frSc8R8toHoS3tQ1xWSvHCvGEADRM9hAm5qmUKjSDX: 98frSc8R8toHoS3tQ1xWSvHCvGEADRM9hAm5qmUKjSDX:
balance: 4 balance: 4
@ -766,13 +766,15 @@ mod tests {
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
file.write_all(yaml_string_pubkey.as_bytes()).unwrap(); file.write_all(yaml_string_pubkey.as_bytes()).unwrap();
let builder = Builder::new(); let mut genesis_block = GenesisBlock::default();
let builder = add_genesis_accounts(
append_primordial_accounts(path.to_str().unwrap(), AccountFileFormat::Pubkey, builder) path.to_str().unwrap(),
.expect("builder"); AccountFileFormat::Pubkey,
&mut genesis_block,
)
.expect("genesis");
remove_file(path).unwrap(); remove_file(path).unwrap();
let genesis_block = builder.clone().build();
assert_eq!(genesis_block.accounts.len(), 4); assert_eq!(genesis_block.accounts.len(), 4);
let yaml_string_keypair = "--- let yaml_string_keypair = "---
@ -797,13 +799,15 @@ mod tests {
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
file.write_all(yaml_string_keypair.as_bytes()).unwrap(); file.write_all(yaml_string_keypair.as_bytes()).unwrap();
let builder = Builder::new(); let mut genesis_block = GenesisBlock::default();
let builder = add_genesis_accounts(
append_primordial_accounts(path.to_str().unwrap(), AccountFileFormat::Keypair, builder) path.to_str().unwrap(),
.expect("builder"); AccountFileFormat::Keypair,
&mut genesis_block,
)
.expect("genesis");
remove_file(path).unwrap(); remove_file(path).unwrap();
let genesis_block = builder.clone().build();
assert_eq!(genesis_block.accounts.len(), 3); assert_eq!(genesis_block.accounts.len(), 3);
} }
} }

View File

@ -56,7 +56,7 @@ impl ConfigState for Config {
} }
} }
pub fn genesis() -> (Pubkey, Account) { pub fn create_genesis_account() -> (Pubkey, Account) {
(id(), create_config_account(vec![], &Config::default(), 100)) (id(), create_config_account(vec![], &Config::default(), 100))
} }
@ -83,7 +83,7 @@ mod tests {
from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &mut account)), from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &mut account)),
Err(InstructionError::InvalidArgument) Err(InstructionError::InvalidArgument)
); );
let (pubkey, mut account) = genesis(); let (pubkey, mut account) = create_genesis_account();
assert_eq!( assert_eq!(
from_keyed_account(&KeyedAccount::new(&pubkey, false, &mut account)), from_keyed_account(&KeyedAccount::new(&pubkey, false, &mut account)),
Ok(Config::default()) Ok(Config::default())

View File

@ -1,3 +1,7 @@
use crate::config::create_genesis_account;
use crate::rewards_pools::create_rewards_accounts;
use solana_sdk::genesis_block::GenesisBlock;
pub mod config; pub mod config;
pub mod rewards_pools; pub mod rewards_pools;
pub mod stake_instruction; pub mod stake_instruction;
@ -13,11 +17,11 @@ solana_sdk::solana_name_id!(
"Stake11111111111111111111111111111111111111" "Stake11111111111111111111111111111111111111"
); );
use solana_sdk::genesis_block::Builder; pub fn add_genesis_accounts(genesis_block: &mut GenesisBlock) {
for (pubkey, account) in create_rewards_accounts() {
genesis_block.add_rewards_pool(pubkey, account);
}
pub fn genesis(mut builder: Builder) -> Builder { let (pubkey, account) = create_genesis_account();
for (pubkey, account) in crate::rewards_pools::genesis().iter() { genesis_block.add_account(pubkey, account);
builder = builder.rewards_pool(*pubkey, account.clone());
}
builder.accounts(&[crate::config::genesis()])
} }

View File

@ -31,7 +31,7 @@ pub fn random_id() -> Pubkey {
Pubkey::new(id.as_ref()) Pubkey::new(id.as_ref())
} }
pub fn genesis() -> Vec<(Pubkey, Account)> { pub fn create_rewards_accounts() -> Vec<(Pubkey, Account)> {
let mut accounts = Vec::with_capacity(NUM_REWARDS_POOLS); let mut accounts = Vec::with_capacity(NUM_REWARDS_POOLS);
let mut pubkey = id(); let mut pubkey = id();
@ -51,7 +51,7 @@ mod tests {
#[test] #[test]
fn test() { fn test() {
let accounts = genesis(); let accounts = create_rewards_accounts();
for _i in 0..NUM_REWARDS_POOLS { for _i in 0..NUM_REWARDS_POOLS {
let id = random_id(); let id = random_id();

View File

@ -5,7 +5,7 @@
use crate::storage_contract::create_rewards_pool; use crate::storage_contract::create_rewards_pool;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use solana_sdk::genesis_block::Builder; use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::hash::{hash, Hash}; use solana_sdk::hash::{hash, Hash};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
@ -20,14 +20,13 @@ solana_sdk::solana_name_id!(ID, "StorageMiningPoo111111111111111111111111111");
// to cut down on collisions for redemptions, we make multiple accounts // to cut down on collisions for redemptions, we make multiple accounts
pub const NUM_REWARDS_POOLS: usize = 32; pub const NUM_REWARDS_POOLS: usize = 32;
pub fn genesis(mut builder: Builder) -> Builder { pub fn add_genesis_accounts(genesis_block: &mut GenesisBlock) {
let mut pubkey = id(); let mut pubkey = id();
for _i in 0..NUM_REWARDS_POOLS { for _i in 0..NUM_REWARDS_POOLS {
builder = builder.rewards_pool(pubkey, create_rewards_pool()); genesis_block.add_rewards_pool(pubkey, create_rewards_pool());
pubkey = Pubkey::new(hash(pubkey.as_ref()).as_ref()); pubkey = Pubkey::new(hash(pubkey.as_ref()).as_ref());
} }
builder
} }
pub fn random_id() -> Pubkey { pub fn random_id() -> Pubkey {
@ -43,13 +42,11 @@ pub fn random_id() -> Pubkey {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use solana_sdk::genesis_block::Builder;
#[test] #[test]
fn test() { fn test() {
let builder = Builder::new(); let mut genesis_block = GenesisBlock::default();
add_genesis_accounts(&mut genesis_block);
let genesis_block = genesis(builder).build();
for _i in 0..NUM_REWARDS_POOLS { for _i in 0..NUM_REWARDS_POOLS {
let id = random_id(); let id = random_id();

View File

@ -1,7 +1,7 @@
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
fee_calculator::FeeCalculator, fee_calculator::FeeCalculator,
genesis_block::{Builder, GenesisBlock}, genesis_block::GenesisBlock,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, KeypairUtil}, signature::{Keypair, KeypairUtil},
system_program::{self, solana_system_program}, system_program::{self, solana_system_program},
@ -47,8 +47,7 @@ pub fn create_genesis_block_with_leader(
bootstrap_leader_stake_lamports, bootstrap_leader_stake_lamports,
); );
let mut builder = Builder::new() let accounts = vec![
.accounts(&[
// the mint // the mint
( (
mint_keypair.pubkey(), mint_keypair.pubkey(),
@ -64,21 +63,29 @@ pub fn create_genesis_block_with_leader(
(voting_keypair.pubkey(), vote_account), (voting_keypair.pubkey(), vote_account),
// passive bootstrap leader stake, duplicates above temporarily // passive bootstrap leader stake, duplicates above temporarily
(staking_keypair.pubkey(), stake_account), (staking_keypair.pubkey(), stake_account),
]) ];
// Bare minimum program set // Bare minimum program set
.native_instruction_processors(&[ let native_instruction_processors = vec![
solana_system_program(), solana_system_program(),
solana_bpf_loader_program!(), solana_bpf_loader_program!(),
solana_vote_program!(), solana_vote_program!(),
solana_stake_program!(), solana_stake_program!(),
]) ];
.fee_calculator(FeeCalculator::new(0, 0)); // most tests don't want fees let fee_calculator = FeeCalculator::new(0, 0); // most tests don't want fees
builder = solana_stake_api::genesis(builder); let mut genesis_block = GenesisBlock {
builder = solana_storage_api::rewards_pools::genesis(builder); accounts,
native_instruction_processors,
fee_calculator,
..GenesisBlock::default()
};
solana_stake_api::add_genesis_accounts(&mut genesis_block);
solana_storage_api::rewards_pools::add_genesis_accounts(&mut genesis_block);
GenesisBlockInfo { GenesisBlockInfo {
genesis_block: builder.build(), genesis_block,
mint_keypair, mint_keypair,
voting_keypair, voting_keypair,
} }

View File

@ -67,79 +67,6 @@ impl Default for GenesisBlock {
} }
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Builder {
genesis_block: GenesisBlock,
}
impl Builder {
pub fn new() -> Self {
Builder::default()
}
// consuming builder because I don't want to clone all the accounts
pub fn build(self) -> GenesisBlock {
self.genesis_block
}
fn append<T: Clone>(items: &[T], mut dest: Vec<T>) -> Vec<T> {
items.iter().cloned().for_each(|item| dest.push(item));
dest
}
pub fn account(self, pubkey: Pubkey, account: Account) -> Self {
self.accounts(&[(pubkey, account)])
}
pub fn accounts(mut self, accounts: &[(Pubkey, Account)]) -> Self {
self.genesis_block.accounts = Self::append(accounts, self.genesis_block.accounts);
self
}
pub fn native_instruction_processor(self, name: &str, pubkey: Pubkey) -> Self {
self.native_instruction_processors(&[(name.to_string(), pubkey)])
}
pub fn native_instruction_processors(
mut self,
native_instruction_processors: &[(String, Pubkey)],
) -> Self {
self.genesis_block.native_instruction_processors = Self::append(
native_instruction_processors,
self.genesis_block.native_instruction_processors,
);
self
}
pub fn rewards_pool(self, pubkey: Pubkey, account: Account) -> Self {
self.rewards_pools(&[(pubkey, account)])
}
pub fn rewards_pools(mut self, rewards_pools: &[(Pubkey, Account)]) -> Self {
self.genesis_block.rewards_pools =
Self::append(rewards_pools, self.genesis_block.rewards_pools);
self
}
pub fn epoch_schedule(mut self, epoch_schedule: EpochSchedule) -> Self {
self.genesis_block.epoch_schedule = epoch_schedule;
self
}
pub fn ticks_per_slot(mut self, ticks_per_slot: u64) -> Self {
self.genesis_block.ticks_per_slot = ticks_per_slot;
self
}
pub fn poh_config(mut self, poh_config: PohConfig) -> Self {
self.genesis_block.poh_config = poh_config;
self
}
pub fn fee_calculator(mut self, fee_calculator: FeeCalculator) -> Self {
self.genesis_block.fee_calculator = fee_calculator;
self
}
pub fn inflation(mut self, inflation: Inflation) -> Self {
self.genesis_block.inflation = inflation;
self
}
pub fn rent_calculator(mut self, rent_calculator: RentCalculator) -> Self {
self.genesis_block.rent_calculator = rent_calculator;
self
}
}
impl GenesisBlock { impl GenesisBlock {
pub fn new( pub fn new(
accounts: &[(Pubkey, Account)], accounts: &[(Pubkey, Account)],
@ -179,6 +106,18 @@ impl GenesisBlock {
let mut file = File::create(&ledger_path.join("genesis.bin"))?; let mut file = File::create(&ledger_path.join("genesis.bin"))?;
file.write_all(&serialized) file.write_all(&serialized)
} }
pub fn add_account(&mut self, pubkey: Pubkey, account: Account) {
self.accounts.push((pubkey, account));
}
pub fn add_native_instruction_processor(&mut self, name: String, program_id: Pubkey) {
self.native_instruction_processors.push((name, program_id));
}
pub fn add_rewards_pool(&mut self, pubkey: Pubkey, account: Account) {
self.rewards_pools.push((pubkey, account));
}
} }
#[cfg(test)] #[cfg(test)]
@ -210,14 +149,13 @@ mod tests {
#[test] #[test]
fn test_genesis_block() { fn test_genesis_block() {
let mint_keypair = Keypair::new(); let mint_keypair = Keypair::new();
let block = Builder::new() let mut block = GenesisBlock::default();
.account( block.add_account(
mint_keypair.pubkey(), mint_keypair.pubkey(),
Account::new(10_000, 0, &Pubkey::default()), Account::new(10_000, 0, &Pubkey::default()),
) );
.accounts(&[(Pubkey::new_rand(), Account::new(1, 0, &Pubkey::default()))]) block.add_account(Pubkey::new_rand(), Account::new(1, 0, &Pubkey::default()));
.native_instruction_processor("hi", Pubkey::new_rand()) block.add_native_instruction_processor("hi".to_string(), Pubkey::new_rand());
.build();
assert_eq!(block.accounts.len(), 2); assert_eq!(block.accounts.len(), 2);
assert!(block.accounts.iter().any( assert!(block.accounts.iter().any(