Move shred_version module to sdk/
This commit is contained in:
@ -7,16 +7,20 @@ use crate::{
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::{hash, Hash},
|
||||
inflation::Inflation,
|
||||
native_token::lamports_to_sol,
|
||||
poh_config::PohConfig,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
shred_version::compute_shred_version,
|
||||
signature::{Keypair, Signer},
|
||||
system_program::{self, solana_system_program},
|
||||
};
|
||||
use bincode::{deserialize, serialize};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use memmap::Mmap;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt,
|
||||
fs::{File, OpenOptions},
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
@ -173,6 +177,51 @@ impl GenesisConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GenesisConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"\
|
||||
Creation time: {}\n\
|
||||
Operating mode: {:?}\n\
|
||||
Genesis hash: {}\n\
|
||||
Shred version: {}\n\
|
||||
Hashes per tick: {:?}\n\
|
||||
Slots per epoch: {}\n\
|
||||
Warmup epochs: {}abled\n\
|
||||
{:?}\n\
|
||||
{:?}\n\
|
||||
Capitalization: {} SOL in {} accounts\n\
|
||||
",
|
||||
Utc.timestamp(self.creation_time, 0).to_rfc3339(),
|
||||
self.operating_mode,
|
||||
self.hash(),
|
||||
compute_shred_version(&self.hash(), None),
|
||||
self.poh_config.hashes_per_tick,
|
||||
self.epoch_schedule.slots_per_epoch,
|
||||
if self.epoch_schedule.warmup {
|
||||
"en"
|
||||
} else {
|
||||
"dis"
|
||||
},
|
||||
self.rent,
|
||||
self.fee_calculator,
|
||||
lamports_to_sol(
|
||||
self.accounts
|
||||
.iter()
|
||||
.map(|(pubkey, account)| {
|
||||
if account.lamports == 0 {
|
||||
panic!("{:?}", (pubkey, account));
|
||||
}
|
||||
account.lamports
|
||||
})
|
||||
.sum::<u64>()
|
||||
),
|
||||
self.accounts.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
91
sdk/src/hard_forks.rs
Normal file
91
sdk/src/hard_forks.rs
Normal file
@ -0,0 +1,91 @@
|
||||
//! The `hard_forks` module is used to maintain the list of slot boundaries for when a hard fork
|
||||
//! should occur.
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use solana_sdk::clock::Slot;
|
||||
use std::ops::Add;
|
||||
|
||||
#[derive(Default, Clone, Deserialize, Serialize)]
|
||||
pub struct HardForks {
|
||||
hard_forks: Vec<(Slot, usize)>,
|
||||
}
|
||||
impl HardForks {
|
||||
// Register a fork to occur at all slots >= `slot` with a parent slot < `slot`
|
||||
pub fn register(&mut self, new_slot: Slot) {
|
||||
if let Some(i) = self
|
||||
.hard_forks
|
||||
.iter()
|
||||
.position(|(slot, _)| *slot == new_slot)
|
||||
{
|
||||
self.hard_forks[i] = (new_slot, self.hard_forks[i].1 + 1);
|
||||
} else {
|
||||
self.hard_forks.push((new_slot, 1));
|
||||
}
|
||||
self.hard_forks.sort();
|
||||
}
|
||||
|
||||
// Returns a sorted-by-slot iterator over the registered hark forks
|
||||
pub fn iter(&self) -> std::slice::Iter<(Slot, usize)> {
|
||||
self.hard_forks.iter()
|
||||
}
|
||||
|
||||
// Returns data to include in the bank hash for the given slot if a hard fork is scheduled
|
||||
pub fn get_hash_data(&self, slot: Slot, parent_slot: Slot) -> Option<[u8; 8]> {
|
||||
// The expected number of hard forks in a cluster is small.
|
||||
// If this turns out to be false then a more efficient data
|
||||
// structure may be needed here to avoid this linear search
|
||||
let fork_count = self
|
||||
.hard_forks
|
||||
.iter()
|
||||
.fold(0, |acc, (fork_slot, fork_count)| {
|
||||
acc.add(if parent_slot < *fork_slot && slot >= *fork_slot {
|
||||
*fork_count
|
||||
} else {
|
||||
0
|
||||
})
|
||||
});
|
||||
|
||||
if fork_count > 0 {
|
||||
let mut buf = [0u8; 8];
|
||||
LittleEndian::write_u64(&mut buf[..], fork_count as u64);
|
||||
Some(buf)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn iter_is_sorted() {
|
||||
let mut hf = HardForks::default();
|
||||
hf.register(30);
|
||||
hf.register(20);
|
||||
hf.register(10);
|
||||
hf.register(20);
|
||||
|
||||
assert_eq!(
|
||||
hf.iter().map(|i| *i).collect::<Vec<_>>(),
|
||||
vec![(10, 1), (20, 2), (30, 1)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_hard_forks_since_parent() {
|
||||
let mut hf = HardForks::default();
|
||||
hf.register(10);
|
||||
hf.register(20);
|
||||
|
||||
assert_eq!(hf.get_hash_data(9, 0), None);
|
||||
assert_eq!(hf.get_hash_data(10, 0), Some([1, 0, 0, 0, 0, 0, 0, 0,]));
|
||||
assert_eq!(hf.get_hash_data(19, 0), Some([1, 0, 0, 0, 0, 0, 0, 0,]));
|
||||
assert_eq!(hf.get_hash_data(20, 0), Some([2, 0, 0, 0, 0, 0, 0, 0,]));
|
||||
assert_eq!(hf.get_hash_data(20, 10), Some([1, 0, 0, 0, 0, 0, 0, 0,]));
|
||||
assert_eq!(hf.get_hash_data(20, 11), Some([1, 0, 0, 0, 0, 0, 0, 0,]));
|
||||
assert_eq!(hf.get_hash_data(21, 11), Some([1, 0, 0, 0, 0, 0, 0, 0,]));
|
||||
assert_eq!(hf.get_hash_data(21, 20), None);
|
||||
}
|
||||
}
|
@ -68,6 +68,10 @@ pub mod client;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod genesis_config;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod hard_forks;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod shred_version;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod signature;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod signers;
|
||||
|
61
sdk/src/shred_version.rs
Normal file
61
sdk/src/shred_version.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use solana_sdk::{
|
||||
hard_forks::HardForks,
|
||||
hash::{extend_and_hash, Hash},
|
||||
};
|
||||
|
||||
pub fn version_from_hash(hash: &Hash) -> u16 {
|
||||
let hash = hash.as_ref();
|
||||
let mut accum = [0u8; 2];
|
||||
hash.chunks(2).for_each(|seed| {
|
||||
accum
|
||||
.iter_mut()
|
||||
.zip(seed)
|
||||
.for_each(|(accum, seed)| *accum ^= *seed)
|
||||
});
|
||||
// convert accum into a u16
|
||||
let version = ((accum[0] as u16) << 8) | accum[1] as u16;
|
||||
|
||||
// ensure version is never zero, to avoid looking like an uninitialized version
|
||||
version.saturating_add(1)
|
||||
}
|
||||
|
||||
pub fn compute_shred_version(genesis_hash: &Hash, hard_forks: Option<&HardForks>) -> u16 {
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
let mut hash = *genesis_hash;
|
||||
if let Some(hard_forks) = hard_forks {
|
||||
for (slot, count) in hard_forks.iter() {
|
||||
let mut buf = [0u8; 16];
|
||||
LittleEndian::write_u64(&mut buf[..8], *slot);
|
||||
LittleEndian::write_u64(&mut buf[8..], *count as u64);
|
||||
hash = extend_and_hash(&hash, &buf);
|
||||
}
|
||||
}
|
||||
|
||||
version_from_hash(&hash)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_compute_shred_version() {
|
||||
assert_eq!(compute_shred_version(&Hash::default(), None), 1);
|
||||
let mut hard_forks = HardForks::default();
|
||||
assert_eq!(
|
||||
compute_shred_version(&Hash::default(), Some(&hard_forks)),
|
||||
1
|
||||
);
|
||||
hard_forks.register(1);
|
||||
assert_eq!(
|
||||
compute_shred_version(&Hash::default(), Some(&hard_forks)),
|
||||
55551
|
||||
);
|
||||
hard_forks.register(1);
|
||||
assert_eq!(
|
||||
compute_shred_version(&Hash::default(), Some(&hard_forks)),
|
||||
46353
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user