1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::account::Account;
use crate::fee_calculator::FeeCalculator;
use crate::hash::{hash, Hash};
use crate::poh_config::PohConfig;
use crate::pubkey::Pubkey;
use crate::signature::{Keypair, KeypairUtil};
use crate::system_program;
use crate::timing::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT};
use std::fs::File;
use std::io::Write;
use std::path::Path;
#[derive(Serialize, Deserialize, Debug)]
pub struct GenesisBlock {
pub accounts: Vec<(Pubkey, Account)>,
pub bootstrap_leader_pubkey: Pubkey,
pub epoch_warmup: bool,
pub fee_calculator: FeeCalculator,
pub native_instruction_processors: Vec<(String, Pubkey)>,
pub slots_per_epoch: u64,
pub stakers_slot_offset: u64,
pub ticks_per_slot: u64,
pub poh_config: PohConfig,
}
pub fn create_genesis_block(lamports: u64) -> (GenesisBlock, Keypair) {
let mint_keypair = Keypair::new();
(
GenesisBlock::new(
&Pubkey::default(),
&[(
mint_keypair.pubkey(),
Account::new(lamports, 0, &system_program::id()),
)],
&[],
),
mint_keypair,
)
}
impl GenesisBlock {
pub fn new(
bootstrap_leader_pubkey: &Pubkey,
accounts: &[(Pubkey, Account)],
native_instruction_processors: &[(String, Pubkey)],
) -> Self {
Self {
accounts: accounts.to_vec(),
bootstrap_leader_pubkey: *bootstrap_leader_pubkey,
epoch_warmup: true,
fee_calculator: FeeCalculator::default(),
native_instruction_processors: native_instruction_processors.to_vec(),
slots_per_epoch: DEFAULT_SLOTS_PER_EPOCH,
stakers_slot_offset: DEFAULT_SLOTS_PER_EPOCH,
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
poh_config: PohConfig::default(),
}
}
pub fn hash(&self) -> Hash {
let serialized = serde_json::to_string(self).unwrap();
hash(&serialized.into_bytes())
}
pub fn load(ledger_path: &str) -> Result<Self, std::io::Error> {
let file = File::open(&Path::new(ledger_path).join("genesis.json"))?;
let genesis_block = serde_json::from_reader(file)?;
Ok(genesis_block)
}
pub fn write(&self, ledger_path: &str) -> Result<(), std::io::Error> {
let serialized = serde_json::to_string(self)?;
let dir = Path::new(ledger_path);
std::fs::create_dir_all(&dir)?;
let mut file = File::create(&dir.join("genesis.json"))?;
file.write_all(&serialized.into_bytes())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::signature::{Keypair, KeypairUtil};
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());
let _ignored = std::fs::remove_dir_all(&path);
let _ignored = std::fs::remove_file(&path);
path
}
#[test]
fn test_genesis_block() {
let mint_keypair = Keypair::new();
let block = GenesisBlock::new(
&Pubkey::default(),
&[
(
mint_keypair.pubkey(),
Account::new(10_000, 0, &Pubkey::default()),
),
(Pubkey::new_rand(), Account::new(1, 0, &Pubkey::default())),
],
&[("hi".to_string(), Pubkey::new_rand())],
);
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);
}
}