| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | //! The `genesis_block` module is a library for generating the chain's genesis block.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  | use crate::account::Account;
 | 
					
						
							| 
									
										
										
										
											2019-05-07 20:28:41 -07:00
										 |  |  | use crate::fee_calculator::FeeCalculator;
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  | use crate::hash::{hash, Hash};
 | 
					
						
							| 
									
										
										
										
											2019-06-11 21:42:31 -07:00
										 |  |  | use crate::inflation::Inflation;
 | 
					
						
							| 
									
										
										
										
											2019-05-18 14:01:36 -07:00
										 |  |  | use crate::poh_config::PohConfig;
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  | use crate::pubkey::Pubkey;
 | 
					
						
							|  |  |  | use crate::signature::{Keypair, KeypairUtil};
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  | use crate::system_program;
 | 
					
						
							| 
									
										
										
										
											2019-07-09 16:48:40 -07:00
										 |  |  | use crate::timing::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT};
 | 
					
						
							| 
									
										
										
										
											2019-06-14 14:22:52 -07:00
										 |  |  | use bincode::{deserialize, serialize};
 | 
					
						
							|  |  |  | use memmap::Mmap;
 | 
					
						
							|  |  |  | use std::fs::{File, OpenOptions};
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | use std::io::Write;
 | 
					
						
							|  |  |  | use std::path::Path;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  | #[derive(Serialize, Deserialize, Debug, Clone)]
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | pub struct GenesisBlock {
 | 
					
						
							| 
									
										
										
										
											2019-05-07 20:28:41 -07:00
										 |  |  |     pub accounts: Vec<(Pubkey, Account)>,
 | 
					
						
							| 
									
										
										
										
											2019-04-02 08:57:00 -06:00
										 |  |  |     pub native_instruction_processors: Vec<(String, Pubkey)>,
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |     pub rewards_pools: Vec<(Pubkey, Account)>,
 | 
					
						
							| 
									
										
										
										
											2019-05-07 20:28:41 -07:00
										 |  |  |     pub slots_per_epoch: u64,
 | 
					
						
							|  |  |  |     pub stakers_slot_offset: u64,
 | 
					
						
							| 
									
										
										
										
											2019-06-11 17:04:13 -07:00
										 |  |  |     pub epoch_warmup: bool,
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |     pub ticks_per_slot: u64,
 | 
					
						
							| 
									
										
										
										
											2019-07-09 16:48:40 -07:00
										 |  |  |     pub slots_per_segment: u64,
 | 
					
						
							| 
									
										
										
										
											2019-05-18 14:01:36 -07:00
										 |  |  |     pub poh_config: PohConfig,
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |     pub fee_calculator: FeeCalculator,
 | 
					
						
							| 
									
										
										
										
											2019-06-11 21:42:31 -07:00
										 |  |  |     pub inflation: Inflation,
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  | // useful for basic tests
 | 
					
						
							|  |  |  | pub fn create_genesis_block(lamports: u64) -> (GenesisBlock, Keypair) {
 | 
					
						
							|  |  |  |     let mint_keypair = Keypair::new();
 | 
					
						
							|  |  |  |     (
 | 
					
						
							|  |  |  |         GenesisBlock::new(
 | 
					
						
							|  |  |  |             &[(
 | 
					
						
							|  |  |  |                 mint_keypair.pubkey(),
 | 
					
						
							|  |  |  |                 Account::new(lamports, 0, &system_program::id()),
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             &[],
 | 
					
						
							|  |  |  |         ),
 | 
					
						
							|  |  |  |         mint_keypair,
 | 
					
						
							|  |  |  |     )
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 17:04:13 -07:00
										 |  |  | impl Default for GenesisBlock {
 | 
					
						
							|  |  |  |     fn default() -> Self {
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							|  |  |  |             accounts: Vec::new(),
 | 
					
						
							|  |  |  |             native_instruction_processors: Vec::new(),
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |             rewards_pools: Vec::new(),
 | 
					
						
							|  |  |  |             epoch_warmup: true,
 | 
					
						
							| 
									
										
										
										
											2019-06-11 17:04:13 -07:00
										 |  |  |             slots_per_epoch: DEFAULT_SLOTS_PER_EPOCH,
 | 
					
						
							|  |  |  |             stakers_slot_offset: DEFAULT_SLOTS_PER_EPOCH,
 | 
					
						
							|  |  |  |             ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
 | 
					
						
							| 
									
										
										
										
											2019-07-09 16:48:40 -07:00
										 |  |  |             slots_per_segment: DEFAULT_SLOTS_PER_SEGMENT,
 | 
					
						
							| 
									
										
										
										
											2019-06-11 17:04:13 -07:00
										 |  |  |             poh_config: PohConfig::default(),
 | 
					
						
							| 
									
										
										
										
											2019-06-11 21:42:31 -07:00
										 |  |  |             inflation: Inflation::default(),
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |             fee_calculator: FeeCalculator::default(),
 | 
					
						
							| 
									
										
										
										
											2019-06-11 17:04:13 -07:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  | #[derive(Serialize, Deserialize, Debug, Default, Clone)]
 | 
					
						
							|  |  |  | pub struct Builder {
 | 
					
						
							|  |  |  |     genesis_block: GenesisBlock,
 | 
					
						
							|  |  |  |     already_have_stakers_slot_offset: bool,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     // also sets stakers_slot_offset, unless already set explicitly
 | 
					
						
							|  |  |  |     pub fn slots_per_epoch(mut self, slots_per_epoch: u64) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.slots_per_epoch = slots_per_epoch;
 | 
					
						
							|  |  |  |         if !self.already_have_stakers_slot_offset {
 | 
					
						
							|  |  |  |             self.genesis_block.stakers_slot_offset = slots_per_epoch;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     pub fn stakers_slot_offset(mut self, stakers_slot_offset: u64) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.stakers_slot_offset = stakers_slot_offset;
 | 
					
						
							|  |  |  |         self.already_have_stakers_slot_offset = true;
 | 
					
						
							|  |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     pub fn epoch_warmup(mut self, epoch_warmup: bool) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.epoch_warmup = epoch_warmup;
 | 
					
						
							|  |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     pub fn ticks_per_slot(mut self, ticks_per_slot: u64) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.ticks_per_slot = ticks_per_slot;
 | 
					
						
							|  |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-06-26 10:13:21 -07:00
										 |  |  |     pub fn poh_config(mut self, poh_config: PohConfig) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.poh_config = poh_config;
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-06-26 10:13:21 -07:00
										 |  |  |     pub fn fee_calculator(mut self, fee_calculator: FeeCalculator) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.fee_calculator = fee_calculator;
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-06-26 10:13:21 -07:00
										 |  |  |     pub fn inflation(mut self, inflation: Inflation) -> Self {
 | 
					
						
							|  |  |  |         self.genesis_block.inflation = inflation;
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  | impl GenesisBlock {
 | 
					
						
							|  |  |  |     pub fn new(
 | 
					
						
							|  |  |  |         accounts: &[(Pubkey, Account)],
 | 
					
						
							|  |  |  |         native_instruction_processors: &[(String, Pubkey)],
 | 
					
						
							|  |  |  |     ) -> Self {
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							| 
									
										
										
										
											2019-05-07 20:28:41 -07:00
										 |  |  |             accounts: accounts.to_vec(),
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  |             native_instruction_processors: native_instruction_processors.to_vec(),
 | 
					
						
							| 
									
										
										
										
											2019-06-11 17:04:13 -07:00
										 |  |  |             ..GenesisBlock::default()
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-01 09:49:37 -08:00
										 |  |  |     pub fn hash(&self) -> Hash {
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  |         let serialized = serde_json::to_string(self).unwrap();
 | 
					
						
							|  |  |  |         hash(&serialized.into_bytes())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn load(ledger_path: &str) -> Result<Self, std::io::Error> {
 | 
					
						
							| 
									
										
										
										
											2019-06-14 14:22:52 -07:00
										 |  |  |         let file = OpenOptions::new()
 | 
					
						
							|  |  |  |             .read(true)
 | 
					
						
							|  |  |  |             .open(&Path::new(ledger_path).join("genesis.bin"))
 | 
					
						
							|  |  |  |             .expect("Unable to open genesis file");
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //UNSAFE: Required to create a Mmap
 | 
					
						
							|  |  |  |         let mem = unsafe { Mmap::map(&file).expect("failed to map the genesis file") };
 | 
					
						
							|  |  |  |         let genesis_block = deserialize(&mem)
 | 
					
						
							|  |  |  |             .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, format!("{:?}", err)))?;
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  |         Ok(genesis_block)
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn write(&self, ledger_path: &str) -> Result<(), std::io::Error> {
 | 
					
						
							| 
									
										
										
										
											2019-06-14 14:22:52 -07:00
										 |  |  |         let serialized = serialize(&self)
 | 
					
						
							|  |  |  |             .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, format!("{:?}", err)))?;
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let dir = Path::new(ledger_path);
 | 
					
						
							|  |  |  |         std::fs::create_dir_all(&dir)?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-14 14:22:52 -07:00
										 |  |  |         let mut file = File::create(&dir.join("genesis.bin"))?;
 | 
					
						
							|  |  |  |         file.write_all(&serialized)
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[cfg(test)]
 | 
					
						
							|  |  |  | mod tests {
 | 
					
						
							|  |  |  |     use super::*;
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  |     use crate::signature::{Keypair, KeypairUtil};
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  |     fn make_tmp_path(name: &str) -> String {
 | 
					
						
							|  |  |  |         let out_dir = std::env::var("OUT_DIR").unwrap_or_else(|_| "target".to_string());
 | 
					
						
							|  |  |  |         let keypair = Keypair::new();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let path = format!("{}/tmp/{}-{}", out_dir, name, keypair.pubkey());
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // whack any possible collision
 | 
					
						
							|  |  |  |         let _ignored = std::fs::remove_dir_all(&path);
 | 
					
						
							|  |  |  |         // whack any possible collision
 | 
					
						
							|  |  |  |         let _ignored = std::fs::remove_file(&path);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         path
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  |     fn test_genesis_block() {
 | 
					
						
							|  |  |  |         let mint_keypair = Keypair::new();
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:40:39 -07:00
										 |  |  |         let block = Builder::new()
 | 
					
						
							|  |  |  |             .account(
 | 
					
						
							|  |  |  |                 mint_keypair.pubkey(),
 | 
					
						
							|  |  |  |                 Account::new(10_000, 0, &Pubkey::default()),
 | 
					
						
							|  |  |  |             )
 | 
					
						
							|  |  |  |             .accounts(&[(Pubkey::new_rand(), Account::new(1, 0, &Pubkey::default()))])
 | 
					
						
							|  |  |  |             .native_instruction_processor("hi", Pubkey::new_rand())
 | 
					
						
							|  |  |  |             .build();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  |         assert_eq!(block.accounts.len(), 2);
 | 
					
						
							|  |  |  |         assert!(block.accounts.iter().any(
 | 
					
						
							|  |  |  |             |(pubkey, account)| *pubkey == mint_keypair.pubkey() && account.lamports == 10_000
 | 
					
						
							|  |  |  |         ));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let path = &make_tmp_path("genesis_block");
 | 
					
						
							|  |  |  |         block.write(&path).expect("write");
 | 
					
						
							|  |  |  |         let loaded_block = GenesisBlock::load(&path).expect("load");
 | 
					
						
							|  |  |  |         assert_eq!(block.hash(), loaded_block.hash());
 | 
					
						
							|  |  |  |         let _ignored = std::fs::remove_file(&path);
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-05-07 11:16:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 12:04:04 -08:00
										 |  |  | }
 |