add epoch_schedule sysvar (#6256)

* add epoch_schedule sysvar

* book sheesh!
This commit is contained in:
Rob Walker 2019-10-08 22:34:26 -07:00 committed by GitHub
parent f2ee01ace3
commit 7cf90766a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 572 additions and 427 deletions

View File

@ -1071,7 +1071,7 @@ mod tests {
#[test]
fn test_bench_tps_fund_keys_with_fees() {
let (mut genesis_block, id) = create_genesis_block(10_000);
let fee_calculator = FeeCalculator::new(11);
let fee_calculator = FeeCalculator::new(11, 0);
genesis_block.fee_calculator = fee_calculator;
let bank = Bank::new(&genesis_block);
let client = BankClient::new(bank);

View File

@ -37,7 +37,8 @@ fn main() {
info!("Generating {} keypairs", *tx_count * 2);
let (keypairs, _) = generate_keypairs(&id, *tx_count as u64 * 2);
let num_accounts = keypairs.len() as u64;
let max_fee = FeeCalculator::new(*target_lamports_per_signature).max_lamports_per_signature;
let max_fee =
FeeCalculator::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee)
/ num_accounts
+ num_lamports_per_account;

View File

@ -3,9 +3,11 @@ set -e
cd "$(dirname "$0")"
make -j"$(nproc)" -B svg
make -j"$(nproc)" -B svg
#TODO figure out why book wants to change, but local and CI differ
exit 0
if [[ -n $CI ]]; then
# In CI confirm that no svgs need to be built
# In CI confirm that no svgs need to be built
git diff --exit-code
fi

View File

@ -61,7 +61,7 @@ test-stable-perf)
_ make -C programs/bpf/c tests
_ cargo +"$rust_stable" test \
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust
--no-default-features --features=bpf_c,bpf_rust -- --nocapture
if [[ $(uname) = Linux ]]; then
# Enable persistence mode to keep the CUDA kernel driver loaded, avoiding a

View File

@ -376,7 +376,7 @@ pub fn parse_command(
Ok(response)
}
pub type ProcessResult = Result<String, Box<dyn error::Error>>;
pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
pub fn check_account_for_fee(
rpc_client: &RpcClient,

View File

@ -9,8 +9,8 @@ use crate::{
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
pubkey::Pubkey, signature::KeypairUtil, system_instruction::SystemError,
transaction::Transaction,
account::Account, epoch_schedule::EpochSchedule, pubkey::Pubkey, signature::KeypairUtil,
system_instruction::SystemError, sysvar, transaction::Transaction,
};
use solana_vote_api::{
vote_instruction::{self, VoteError},
@ -277,12 +277,26 @@ pub fn process_vote_authorize(
log_instruction_custom_error::<VoteError>(result)
}
pub fn process_show_vote_account(
fn get_epoch_schedule(rpc_client: &RpcClient) -> Result<EpochSchedule, Box<dyn std::error::Error>> {
let epoch_schedule_account = rpc_client.get_account(&sysvar::epoch_schedule::id())?;
if epoch_schedule_account.owner != sysvar::id() {
return Err(CliError::RpcRequestError(format!(
"{:?} is not an epoch_schedule account",
sysvar::epoch_schedule::id()
))
.into());
}
let epoch_schedule = EpochSchedule::deserialize(&epoch_schedule_account)?;
Ok(epoch_schedule)
}
fn get_vote_account(
rpc_client: &RpcClient,
_config: &CliConfig,
vote_account_pubkey: &Pubkey,
use_lamports_unit: bool,
) -> ProcessResult {
) -> Result<(Account, VoteState), Box<dyn std::error::Error>> {
let vote_account = rpc_client.get_account(vote_account_pubkey)?;
if vote_account.owner != solana_vote_api::id() {
@ -291,13 +305,25 @@ pub fn process_show_vote_account(
)
.into());
}
let vote_state = VoteState::deserialize(&vote_account.data).map_err(|_| {
CliError::RpcRequestError(
"Account data could not be deserialized to vote state".to_string(),
)
})?;
Ok((vote_account, vote_state))
}
pub fn process_show_vote_account(
rpc_client: &RpcClient,
_config: &CliConfig,
vote_account_pubkey: &Pubkey,
use_lamports_unit: bool,
) -> ProcessResult {
let (vote_account, vote_state) = get_vote_account(rpc_client, vote_account_pubkey)?;
let epoch_schedule = get_epoch_schedule(rpc_client)?;
println!(
"account balance: {}",
build_balance_message(vote_account.lamports, use_lamports_unit)
@ -329,14 +355,6 @@ pub fn process_show_vote_account(
);
}
// TODO: Use the real GenesisBlock from the cluster.
let genesis_block = solana_sdk::genesis_block::GenesisBlock::default();
let epoch_schedule = solana_runtime::epoch_schedule::EpochSchedule::new(
genesis_block.slots_per_epoch,
genesis_block.stakers_slot_offset,
genesis_block.epoch_warmup,
);
println!("epoch voting history:");
for (epoch, credits, prev_credits) in vote_state.epoch_credits() {
let credits_earned = credits - prev_credits;
@ -357,34 +375,15 @@ pub fn process_uptime(
aggregate: bool,
span: Option<u64>,
) -> ProcessResult {
let vote_account = rpc_client.get_account(vote_account_pubkey)?;
let (_vote_account, vote_state) = get_vote_account(rpc_client, vote_account_pubkey)?;
if vote_account.owner != solana_vote_api::id() {
return Err(CliError::RpcRequestError(
format!("{:?} is not a vote account", vote_account_pubkey).to_string(),
)
.into());
}
let vote_state = VoteState::deserialize(&vote_account.data).map_err(|_| {
CliError::RpcRequestError(
"Account data could not be deserialized to vote state".to_string(),
)
})?;
let epoch_schedule = get_epoch_schedule(rpc_client)?;
println!("Node id: {}", vote_state.node_pubkey);
println!("Authorized voter: {}", vote_state.authorized_voter);
if !vote_state.votes.is_empty() {
println!("Uptime:");
// TODO: Use the real GenesisBlock from the cluster.
let genesis_block = solana_sdk::genesis_block::GenesisBlock::default();
let epoch_schedule = solana_runtime::epoch_schedule::EpochSchedule::new(
genesis_block.slots_per_epoch,
genesis_block.stakers_slot_offset,
genesis_block.epoch_warmup,
);
let epoch_credits_vec: Vec<(u64, u64, u64)> = vote_state.epoch_credits().copied().collect();
let epoch_credits = if let Some(x) = span {

View File

@ -462,20 +462,21 @@ fn process_pending_slots(
#[cfg(test)]
pub mod tests {
use super::*;
use crate::blocktree::create_new_tmp_ledger;
use crate::entry::{create_ticks, next_entry, next_entry_mut, Entry};
use crate::genesis_utils::{
create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo,
use crate::{
blocktree::create_new_tmp_ledger,
entry::{create_ticks, next_entry, next_entry_mut, Entry},
genesis_utils::{create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo},
};
use rand::{thread_rng, Rng};
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::hash::Hash;
use solana_sdk::instruction::InstructionError;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction;
use solana_sdk::transaction::Transaction;
use solana_sdk::transaction::TransactionError;
use solana_sdk::{
epoch_schedule::EpochSchedule,
hash::Hash,
instruction::InstructionError,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
system_transaction,
transaction::{Transaction, TransactionError},
};
use std::sync::RwLock;
pub fn fill_blocktree_slot_with_ticks(

View File

@ -62,7 +62,7 @@ impl BroadcastRun for FailEntryVerificationBroadcastRun {
.expect("Failed to insert shreds in blocktree");
// 3) Start broadcast step
let bank_epoch = bank.get_stakers_epoch(bank.slot());
let bank_epoch = bank.get_leader_schedule_epoch(bank.slot());
let stakes = staking_utils::staked_nodes_at_epoch(&bank, bank_epoch);
let all_shred_bufs: Vec<Vec<u8>> = data_shreds

View File

@ -192,7 +192,7 @@ impl BroadcastRun for StandardBroadcastRun {
// 3) Start broadcast step
let broadcast_start = Instant::now();
let bank_epoch = bank.get_stakers_epoch(bank.slot());
let bank_epoch = bank.get_leader_schedule_epoch(bank.slot());
let stakes = staking_utils::staked_nodes_at_epoch(&bank, bank_epoch);
let all_shred_bufs: Vec<Vec<u8>> = data_shreds

View File

@ -8,17 +8,18 @@ use rand::seq::SliceRandom;
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use solana_metrics::datapoint;
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::pubkey::Pubkey;
use std::cmp;
use std::collections::HashMap;
use std::mem;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::{self, sleep, Builder, JoinHandle};
use std::time::Duration;
use solana_sdk::{epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
cmp,
collections::HashMap,
mem,
net::SocketAddr,
net::UdpSocket,
sync::atomic::{AtomicBool, Ordering},
sync::{Arc, RwLock},
thread::{self, sleep, Builder, JoinHandle},
time::Duration,
};
pub const REPAIRMEN_SLEEP_MILLIS: usize = 100;
pub const REPAIR_REDUNDANCY: usize = 1;
@ -278,7 +279,7 @@ impl ClusterInfoRepairListener {
let mut total_coding_blobs_sent = 0;
let mut num_slots_repaired = 0;
let max_confirmed_repairee_epoch =
epoch_schedule.get_stakers_epoch(repairee_epoch_slots.root);
epoch_schedule.get_leader_schedule_epoch(repairee_epoch_slots.root);
let max_confirmed_repairee_slot =
epoch_schedule.get_last_slot_in_epoch(max_confirmed_repairee_epoch);
@ -655,7 +656,7 @@ mod tests {
let eligible_repairmen_refs: Vec<_> = eligible_repairmen.iter().collect();
// Have all the repairman send the repairs
let epoch_schedule = EpochSchedule::new(32, 16, false);
let epoch_schedule = EpochSchedule::custom(32, 16, false);
let num_missing_slots = num_slots / 2;
for repairman_pubkey in &eligible_repairmen {
ClusterInfoRepairListener::serve_repairs_to_repairee(
@ -699,7 +700,7 @@ mod tests {
let blocktree = Blocktree::open(&blocktree_path).unwrap();
let stakers_slot_offset = 16;
let slots_per_epoch = stakers_slot_offset * 2;
let epoch_schedule = EpochSchedule::new(slots_per_epoch, stakers_slot_offset, false);
let epoch_schedule = EpochSchedule::custom(slots_per_epoch, stakers_slot_offset, false);
// Create blobs for first two epochs and write them to blocktree
let total_slots = slots_per_epoch * 2;

View File

@ -1,12 +1,10 @@
use crate::blocktree::Blocktree;
use crate::leader_schedule::LeaderSchedule;
use crate::leader_schedule_utils;
use crate::{blocktree::Blocktree, leader_schedule::LeaderSchedule, leader_schedule_utils};
use solana_runtime::bank::Bank;
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::pubkey::Pubkey;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, RwLock};
use solana_sdk::{epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
collections::{hash_map::Entry, HashMap, VecDeque},
sync::{Arc, RwLock},
};
type CachedSchedules = (HashMap<u64, Arc<LeaderSchedule>>, VecDeque<u64>);
const MAX_SCHEDULES: usize = 10;
@ -40,11 +38,11 @@ impl LeaderScheduleCache {
max_schedules: CacheCapacity::default(),
};
// This sets the root and calculates the schedule at stakers_epoch(root)
// This sets the root and calculates the schedule at leader_schedule_epoch(root)
cache.set_root(root_bank);
// Calculate the schedule for all epochs between 0 and stakers_epoch(root)
let stakers_epoch = epoch_schedule.get_stakers_epoch(root_bank.slot());
// Calculate the schedule for all epochs between 0 and leader_schedule_epoch(root)
let stakers_epoch = epoch_schedule.get_leader_schedule_epoch(root_bank.slot());
for epoch in 0..stakers_epoch {
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
cache.slot_leader_at(first_slot_in_epoch, Some(root_bank));
@ -63,7 +61,9 @@ impl LeaderScheduleCache {
}
pub fn set_root(&self, root_bank: &Bank) {
let new_max_epoch = self.epoch_schedule.get_stakers_epoch(root_bank.slot());
let new_max_epoch = self
.epoch_schedule
.get_leader_schedule_epoch(root_bank.slot());
let old_max_epoch = {
let mut max_epoch = self.max_epoch.write().unwrap();
let old_max_epoch = *max_epoch;
@ -229,19 +229,20 @@ impl LeaderScheduleCache {
#[cfg(test)]
mod tests {
use super::*;
use crate::blocktree::tests::make_slot_entries;
use crate::genesis_utils::create_genesis_block;
use crate::genesis_utils::{
create_genesis_block_with_leader, GenesisBlockInfo, BOOTSTRAP_LEADER_LAMPORTS,
use crate::{
blocktree::{get_tmp_ledger_path, tests::make_slot_entries},
genesis_utils::{
create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo,
BOOTSTRAP_LEADER_LAMPORTS,
},
staking_utils::tests::setup_vote_and_stake_accounts,
};
use crate::staking_utils::tests::setup_vote_and_stake_accounts;
use solana_runtime::bank::Bank;
use solana_runtime::epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread::Builder;
use crate::blocktree::get_tmp_ledger_path;
use solana_sdk::epoch_schedule::{
EpochSchedule, DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET, DEFAULT_SLOTS_PER_EPOCH,
MINIMUM_SLOTS_PER_EPOCH,
};
use std::{sync::mpsc::channel, sync::Arc, thread::Builder};
#[test]
fn test_new_cache() {
@ -255,7 +256,7 @@ mod tests {
// [0, stakers_epoch(bank.slot())] should
// be calculated by constructor
let epoch_schedule = bank.epoch_schedule();
let stakers_epoch = bank.get_stakers_epoch(bank.slot());
let stakers_epoch = bank.get_leader_schedule_epoch(bank.slot());
for epoch in 0..=stakers_epoch {
let first_slot_in_stakers_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
let last_slot_in_stakers_epoch = epoch_schedule.get_last_slot_in_epoch(epoch);
@ -307,7 +308,7 @@ mod tests {
fn run_thread_race() {
let slots_per_epoch = MINIMUM_SLOTS_PER_EPOCH as u64;
let epoch_schedule = EpochSchedule::new(slots_per_epoch, slots_per_epoch / 2, true);
let epoch_schedule = EpochSchedule::custom(slots_per_epoch, slots_per_epoch / 2, true);
let GenesisBlockInfo { genesis_block, .. } = create_genesis_block(2);
let bank = Arc::new(Bank::new(&genesis_block));
let cache = Arc::new(LeaderScheduleCache::new(epoch_schedule, &bank));
@ -353,7 +354,11 @@ mod tests {
BOOTSTRAP_LEADER_LAMPORTS,
)
.genesis_block;
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule = EpochSchedule::custom(
DEFAULT_SLOTS_PER_EPOCH,
DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET,
false,
);
let bank = Bank::new(&genesis_block);
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
@ -373,7 +378,7 @@ mod tests {
assert_eq!(
cache.next_leader_slot(
&pubkey,
2 * genesis_block.slots_per_epoch - 1, // no schedule generated for epoch 2
2 * genesis_block.epoch_schedule.slots_per_epoch - 1, // no schedule generated for epoch 2
&bank,
None
),
@ -400,7 +405,7 @@ mod tests {
BOOTSTRAP_LEADER_LAMPORTS,
)
.genesis_block;
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule.warmup = false;
let bank = Bank::new(&genesis_block);
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
@ -452,7 +457,7 @@ mod tests {
assert_eq!(
cache.next_leader_slot(
&pubkey,
2 * genesis_block.slots_per_epoch - 1, // no schedule generated for epoch 2
2 * genesis_block.epoch_schedule.slots_per_epoch - 1, // no schedule generated for epoch 2
&bank,
Some(&blocktree)
),
@ -479,7 +484,7 @@ mod tests {
mint_keypair,
..
} = create_genesis_block(10_000);
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule.warmup = false;
let bank = Bank::new(&genesis_block);
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
@ -498,14 +503,14 @@ mod tests {
// Have to wait until the epoch at after the epoch stakes generated at genesis
// for the new votes to take effect.
let mut target_slot = 1;
let epoch = bank.get_stakers_epoch(0);
while bank.get_stakers_epoch(target_slot) == epoch {
let epoch = bank.get_leader_schedule_epoch(0);
while bank.get_leader_schedule_epoch(target_slot) == epoch {
target_slot += 1;
}
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default(), target_slot);
let mut expected_slot = 0;
let epoch = bank.get_stakers_epoch(target_slot);
let epoch = bank.get_leader_schedule_epoch(target_slot);
for i in 0..epoch {
expected_slot += bank.get_slots_in_epoch(i);
}
@ -514,7 +519,7 @@ mod tests {
let mut index = 0;
while schedule[index] != node_pubkey {
index += 1;
assert_ne!(index, genesis_block.slots_per_epoch);
assert_ne!(index, genesis_block.epoch_schedule.slots_per_epoch);
}
expected_slot += index;

View File

@ -69,7 +69,7 @@ mod tests {
let leader_schedule = LeaderSchedule::new(
&pubkeys_and_stakes,
seed,
genesis_block.slots_per_epoch,
genesis_block.epoch_schedule.slots_per_epoch,
NUM_CONSECUTIVE_LEADER_SLOTS,
);

View File

@ -1,22 +1,24 @@
//! The `repair_service` module implements the tools necessary to generate a thread which
//! regularly finds missing blobs in the ledger and sends repair requests for those blobs
use crate::bank_forks::BankForks;
use crate::blocktree::{Blocktree, CompletedSlotsReceiver, SlotMeta};
use crate::cluster_info::ClusterInfo;
use crate::cluster_info_repair_listener::ClusterInfoRepairListener;
use crate::result::Result;
use crate::service::Service;
use solana_metrics::datapoint_debug;
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::pubkey::Pubkey;
use std::collections::BTreeSet;
use std::net::UdpSocket;
use std::ops::Bound::{Excluded, Unbounded};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;
use crate::{
bank_forks::BankForks,
blocktree::{Blocktree, CompletedSlotsReceiver, SlotMeta},
cluster_info::ClusterInfo,
cluster_info_repair_listener::ClusterInfoRepairListener,
result::Result,
service::Service,
};
use solana_sdk::{epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
collections::BTreeSet,
net::UdpSocket,
ops::Bound::{Excluded, Unbounded},
sync::atomic::{AtomicBool, Ordering},
sync::{Arc, RwLock},
thread::sleep,
thread::{self, Builder, JoinHandle},
time::Duration,
};
pub const MAX_REPAIR_LENGTH: usize = 16;
pub const REPAIR_MS: u64 = 100;
@ -299,7 +301,7 @@ impl RepairService {
root: u64,
epoch_schedule: &EpochSchedule,
) {
let last_confirmed_epoch = epoch_schedule.get_stakers_epoch(root);
let last_confirmed_epoch = epoch_schedule.get_leader_schedule_epoch(root);
let last_epoch_slot = epoch_schedule.get_last_slot_in_epoch(last_confirmed_epoch);
let meta_iter = blocktree
@ -652,7 +654,7 @@ mod test {
.unwrap();
// Test that only slots > root from fork1 were included
let epoch_schedule = EpochSchedule::new(32, 32, false);
let epoch_schedule = EpochSchedule::custom(32, 32, false);
RepairService::get_completed_slots_past_root(
&blocktree,
@ -665,7 +667,7 @@ mod test {
assert_eq!(full_slots, expected);
// Test that slots past the last confirmed epoch boundary don't get included
let last_epoch = epoch_schedule.get_stakers_epoch(root);
let last_epoch = epoch_schedule.get_leader_schedule_epoch(root);
let last_slot = epoch_schedule.get_last_slot_in_epoch(last_epoch);
let fork3 = vec![last_slot, last_slot + 1];
let fork3_shreds: Vec<_> = make_chaining_slot_entries(&fork3, num_entries_per_slot)

View File

@ -1005,7 +1005,7 @@ mod test {
create_genesis_block_with_leader(50, &leader_pubkey, leader_lamports);
let mut genesis_block = genesis_block_info.genesis_block;
let leader_voting_pubkey = genesis_block_info.voting_keypair.pubkey();
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule.warmup = false;
genesis_block.ticks_per_slot = 4;
let bank0 = Bank::new(&genesis_block);
for _ in 1..genesis_block.ticks_per_slot {

View File

@ -1,28 +1,32 @@
//! The `retransmit_stage` retransmits blobs between validators
use crate::bank_forks::BankForks;
use crate::blocktree::{Blocktree, CompletedSlotsReceiver};
use crate::cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT};
use crate::leader_schedule_cache::LeaderScheduleCache;
use crate::repair_service::RepairStrategy;
use crate::result::{Error, Result};
use crate::service::Service;
use crate::staking_utils;
use crate::streamer::PacketReceiver;
use crate::window_service::{should_retransmit_and_persist, WindowService};
use crate::{
bank_forks::BankForks,
blocktree::{Blocktree, CompletedSlotsReceiver},
cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT},
leader_schedule_cache::LeaderScheduleCache,
repair_service::RepairStrategy,
result::{Error, Result},
service::Service,
staking_utils,
streamer::PacketReceiver,
window_service::{should_retransmit_and_persist, WindowService},
};
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use solana_measure::measure::Measure;
use solana_metrics::{datapoint_debug, inc_new_counter_error};
use solana_runtime::epoch_schedule::EpochSchedule;
use std::cmp;
use std::net::UdpSocket;
use std::sync::atomic::AtomicBool;
use std::sync::mpsc::channel;
use std::sync::mpsc::RecvTimeoutError;
use std::sync::{Arc, RwLock};
use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;
use solana_metrics::inc_new_counter_error;
use solana_sdk::epoch_schedule::EpochSchedule;
use std::{
cmp,
net::UdpSocket,
sync::atomic::AtomicBool,
sync::mpsc::channel,
sync::mpsc::RecvTimeoutError,
sync::{Arc, RwLock},
thread::{self, Builder, JoinHandle},
time::Duration,
};
pub fn retransmit(
bank_forks: &Arc<RwLock<BankForks>>,
@ -42,7 +46,7 @@ pub fn retransmit(
}
let r_bank = bank_forks.read().unwrap().working_bank();
let bank_epoch = r_bank.get_stakers_epoch(r_bank.slot());
let bank_epoch = r_bank.get_leader_schedule_epoch(r_bank.slot());
let mut peers_len = 0;
let stakes = staking_utils::staked_nodes_at_epoch(&r_bank, bank_epoch);
let (peers, stakes_and_index) = cluster_info

View File

@ -211,27 +211,27 @@ pub(crate) mod tests {
..Stake::default()
};
let first_stakers_epoch = bank.get_stakers_epoch(bank.slot());
// find the first slot in the next staker's epoch
let first_leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
// find the first slot in the next leader schedule epoch
let mut slot = bank.slot();
loop {
slot += 1;
if bank.get_stakers_epoch(slot) != first_stakers_epoch {
if bank.get_leader_schedule_epoch(slot) != first_leader_schedule_epoch {
break;
}
}
let bank = new_from_parent(&Arc::new(bank), slot);
let next_stakers_epoch = bank.get_stakers_epoch(slot);
let next_leader_schedule_epoch = bank.get_leader_schedule_epoch(slot);
let result: Vec<_> = epoch_stakes_and_lockouts(&bank, first_stakers_epoch);
let result: Vec<_> = epoch_stakes_and_lockouts(&bank, first_leader_schedule_epoch);
assert_eq!(
result,
vec![(leader_stake.stake(first_stakers_epoch, None), None)]
vec![(leader_stake.stake(first_leader_schedule_epoch, None), None)]
);
// epoch stakes and lockouts are saved off for the future epoch, should
// match current bank state
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, next_stakers_epoch);
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, next_leader_schedule_epoch);
result.sort();
let stake_history =
StakeHistory::from_account(&bank.get_account(&stake_history::id()).unwrap()).unwrap();

View File

@ -296,8 +296,8 @@ mod test {
shred::SIZE_OF_SHRED_TYPE,
};
use rand::{seq::SliceRandom, thread_rng};
use solana_runtime::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
use solana_sdk::{
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
hash::Hash,
signature::{Keypair, KeypairUtil},
};

View File

@ -4,27 +4,31 @@ use base64;
use clap::{crate_description, crate_name, crate_version, value_t_or_exit, App, Arg};
use solana_core::blocktree::create_new_ledger;
use solana_genesis::PrimordialAccountDetails;
use solana_sdk::account::Account;
use solana_sdk::clock;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::genesis_block::Builder;
use solana_sdk::hash::{hash, Hash};
use solana_sdk::poh_config::PohConfig;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::rent_calculator::RentCalculator;
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
use solana_sdk::system_program;
use solana_sdk::timing;
use solana_sdk::{
account::Account,
clock,
epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator,
genesis_block::Builder,
hash::{hash, Hash},
poh_config::PohConfig,
pubkey::Pubkey,
rent_calculator::RentCalculator,
signature::{read_keypair, Keypair, KeypairUtil},
system_program, timing,
};
use solana_stake_api::stake_state;
use solana_storage_api::storage_contract;
use solana_vote_api::vote_state;
use std::collections::HashMap;
use std::error;
use std::fs::File;
use std::io;
use std::path::PathBuf;
use std::str::FromStr;
use std::time::{Duration, Instant};
use std::{
collections::HashMap,
error,
fs::File,
io,
path::PathBuf,
str::FromStr,
time::{Duration, Instant},
};
pub const BOOTSTRAP_LEADER_LAMPORTS: u64 = 42;
@ -87,18 +91,18 @@ fn main() -> Result<(), Box<dyn error::Error>> {
let default_target_lamports_per_signature = &FeeCalculator::default()
.target_lamports_per_signature
.to_string();
let default_target_signatures_per_slot = &FeeCalculator::default()
.target_signatures_per_slot
.to_string();
let default_lamports_per_byte_year =
&RentCalculator::default().lamports_per_byte_year.to_string();
let default_rent_exemption_threshold =
&RentCalculator::default().exemption_threshold.to_string();
let default_rent_burn_percentage = &RentCalculator::default().burn_percent.to_string();
let default_target_signatures_per_slot = &FeeCalculator::default()
.target_signatures_per_slot
.to_string();
let default_target_tick_duration =
&timing::duration_as_ms(&PohConfig::default().target_tick_duration).to_string();
let default_ticks_per_slot = &clock::DEFAULT_TICKS_PER_SLOT.to_string();
let default_slots_per_epoch = &clock::DEFAULT_SLOTS_PER_EPOCH.to_string();
let default_slots_per_epoch = &EpochSchedule::default().slots_per_epoch.to_string();
let matches = App::new(crate_name!())
.about(crate_description!())
@ -346,15 +350,18 @@ fn main() -> Result<(), Box<dyn error::Error>> {
),
])
.native_instruction_processors(&solana_genesis_programs::get())
.ticks_per_slot(value_t_or_exit!(matches, "ticks_per_slot", u64))
.slots_per_epoch(value_t_or_exit!(matches, "slots_per_epoch", u64));
.ticks_per_slot(value_t_or_exit!(matches, "ticks_per_slot", u64));
let mut fee_calculator = FeeCalculator::default();
fee_calculator.target_lamports_per_signature =
value_t_or_exit!(matches, "target_lamports_per_signature", u64);
fee_calculator.target_signatures_per_slot =
value_t_or_exit!(matches, "target_signatures_per_slot", usize);
builder = builder.fee_calculator(FeeCalculator::new_derived(&fee_calculator, 0));
let slots_per_epoch = value_t_or_exit!(matches, "slots_per_epoch", u64);
let epoch_schedule = EpochSchedule::new(slots_per_epoch);
builder = builder.epoch_schedule(epoch_schedule);
let fee_calculator = FeeCalculator::new(
value_t_or_exit!(matches, "target_lamports_per_signature", u64),
value_t_or_exit!(matches, "target_signatures_per_slot", usize),
);
builder = builder.fee_calculator(fee_calculator);
let rent_calculator = RentCalculator {
lamports_per_byte_year: value_t_or_exit!(matches, "lamports_per_byte_year", u64),

View File

@ -12,10 +12,10 @@ use solana_core::{
entry::{Entry, EntrySlice},
gossip_service::discover_cluster,
};
use solana_runtime::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
use solana_sdk::{
client::SyncClient,
clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, NUM_CONSECUTIVE_LEADER_SLOTS},
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
hash::Hash,
poh_config::PohConfig,
pubkey::Pubkey,

View File

@ -13,6 +13,7 @@ use solana_core::{
use solana_sdk::{
client::SyncClient,
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
epoch_schedule::EpochSchedule,
genesis_block::GenesisBlock,
message::Message,
poh_config::PohConfig,
@ -138,9 +139,9 @@ impl LocalCluster {
config.node_stakes[0],
);
genesis_block.ticks_per_slot = config.ticks_per_slot;
genesis_block.slots_per_epoch = config.slots_per_epoch;
genesis_block.slots_per_segment = config.slots_per_segment;
genesis_block.stakers_slot_offset = config.stakers_slot_offset;
genesis_block.epoch_schedule =
EpochSchedule::custom(config.slots_per_epoch, config.stakers_slot_offset, true);
genesis_block.poh_config = config.poh_config.clone();
genesis_block
.native_instruction_processors
@ -638,7 +639,7 @@ impl Drop for LocalCluster {
mod test {
use super::*;
use solana_core::storage_stage::SLOTS_PER_TURN_TEST;
use solana_runtime::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
use solana_sdk::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
#[test]
fn test_local_cluster_start_and_exit() {

View File

@ -9,11 +9,13 @@ use solana_core::{
bank_forks::SnapshotConfig, blocktree::Blocktree, broadcast_stage::BroadcastStageType,
gossip_service::discover_cluster, snapshot_utils, validator::ValidatorConfig,
};
use solana_runtime::{
accounts_db::AccountsDB,
use solana_runtime::accounts_db::AccountsDB;
use solana_sdk::{
client::SyncClient,
clock,
epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH},
poh_config::PohConfig,
};
use solana_sdk::{client::SyncClient, clock, poh_config::PohConfig};
use std::path::{Path, PathBuf};
use std::{
collections::{HashMap, HashSet},
@ -548,12 +550,12 @@ fn test_faulty_node(faulty_node_type: BroadcastStageType) {
};
let cluster = LocalCluster::new(&cluster_config);
let epoch_schedule = EpochSchedule::new(
let epoch_schedule = EpochSchedule::custom(
cluster_config.slots_per_epoch,
cluster_config.stakers_slot_offset,
true,
);
let num_warmup_epochs = epoch_schedule.get_stakers_epoch(0) + 1;
let num_warmup_epochs = epoch_schedule.get_leader_schedule_epoch(0) + 1;
// Wait for the corrupted leader to be scheduled afer the warmup epochs expire
cluster_tests::sleep_n_epochs(
@ -636,8 +638,8 @@ fn run_repairman_catchup(num_repairmen: u64) {
});
let repairman_pubkeys: HashSet<_> = cluster.get_node_pubkeys().into_iter().collect();
let epoch_schedule = EpochSchedule::new(num_slots_per_epoch, stakers_slot_offset, true);
let num_warmup_epochs = epoch_schedule.get_stakers_epoch(0) + 1;
let epoch_schedule = EpochSchedule::custom(num_slots_per_epoch, stakers_slot_offset, true);
let num_warmup_epochs = epoch_schedule.get_leader_schedule_epoch(0) + 1;
// Sleep for longer than the first N warmup epochs, with a one epoch buffer for timing issues
cluster_tests::sleep_n_epochs(

View File

@ -323,7 +323,7 @@ dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1332,7 +1332,7 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.9.20"
version = "0.9.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1350,7 +1350,7 @@ dependencies = [
"mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1474,7 +1474,7 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.40"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1697,7 +1697,7 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-ed25519-dalek 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1740,7 +1740,7 @@ dependencies = [
"env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-sdk 0.20.0",
"sys-info 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1772,7 +1772,7 @@ dependencies = [
"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_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-bpf-loader-api 0.20.0",
"solana-bpf-loader-program 0.20.0",
"solana-logger 0.20.0",
@ -1810,7 +1810,7 @@ dependencies = [
"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_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-crate-features 0.20.0",
"solana-ed25519-dalek 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2647,7 +2647,7 @@ dependencies = [
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0f6d896143a583047512e59ac54a215cb203c29cc941917343edea3be8df9c78"
"checksum reqwest 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)" = "02b7e953e14c6f3102b7e8d1f1ee3abf5ecee80b427f5565c9389835cecae95c"
"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb"
"checksum ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6747f8da1f2b1fabbee1aaa4eb8a11abf9adef0bf58a41cee45db5d59cecdfac"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
@ -2662,7 +2662,7 @@ dependencies = [
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0"
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"

View File

@ -28,7 +28,7 @@ perform_action() {
set -e
case "$1" in
build)
"$sdkDir"/bpf/rust/build.sh "$2"
bash -x "$sdkDir"/bpf/rust/build.sh "$2"
so_path="$targetDir/$profile/"
so_name="solana_bpf_rust_${3%/}"

View File

@ -17,7 +17,7 @@ use solana_sdk::{
entrypoint!(process_instruction);
fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], _data: &[u8]) -> u32 {
// Clock
let clock = Clock::from_account_info(&accounts[2]).unwrap();
let clock = Clock::from_account_info(&accounts[2]).expect("clock");
assert_eq!(clock.slot, DEFAULT_SLOTS_PER_EPOCH + 1);
assert_eq!(
clock.segment,
@ -25,20 +25,20 @@ fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], _data
);
// Fees
let fees = Fees::from_account_info(&accounts[3]).unwrap();
let fees = Fees::from_account_info(&accounts[3]).expect("fees");
let burn = fees.fee_calculator.burn(42);
assert_eq!(burn, (21, 21));
// Rewards
let _ = Rewards::from_account_info(&accounts[4]).unwrap();
let _rewards = Rewards::from_account_info(&accounts[4]).expect("rewards");
// Slot Hashes
let slot_hashes = SlotHashes::from_account_info(&accounts[5]).unwrap();
assert_eq!(slot_hashes.len(), 1);
let slot_hashes = SlotHashes::from_account_info(&accounts[5]).expect("slot_hashes");
assert!(slot_hashes.len() >= 1);
// Stake History
let stake_history = StakeHistory::from_account_info(&accounts[6]).unwrap();
assert_eq!(stake_history.len(), 1);
let stake_history = StakeHistory::from_account_info(&accounts[6]).expect("stake_history");
assert!(stake_history.len() >= 1);
let rent = Rent::from_account_info(&accounts[7]).unwrap();
assert_eq!(

View File

@ -111,15 +111,16 @@ mod bpf {
file.read_to_end(&mut elf).unwrap();
let GenesisBlockInfo {
mut genesis_block,
genesis_block,
mint_keypair,
..
} = create_genesis_block(50);
genesis_block.epoch_warmup = false;
let bank = Arc::new(Bank::new(&genesis_block));
// Create bank with specific slot, used by solana_bpf_rust_sysvar test
dbg!(bank.epoch());
let bank =
Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
dbg!(bank.epoch());
let bank_client = BankClient::new(bank);
// Call user program

View File

@ -252,7 +252,7 @@ fn test_stake_account_delegate() {
let mut bank = Bank::new_from_parent(
&bank,
&Pubkey::default(),
genesis_block.slots_per_epoch * 10 + bank.slot(),
genesis_block.epoch_schedule.slots_per_epoch * 10 + bank.slot(),
);
bank.add_instruction_processor(id(), process_instruction);
let bank = Arc::new(bank);

View File

@ -4,7 +4,6 @@ use crate::{id, vote_instruction::VoteError};
use bincode::{deserialize, serialize_into, serialized_size, ErrorKind};
use log::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::sysvar::slot_hashes::SlotHash;
use solana_sdk::{
account::{Account, KeyedAccount},
account_utils::State,
@ -12,11 +11,12 @@ use solana_sdk::{
hash::Hash,
instruction::InstructionError,
pubkey::Pubkey,
slot_hashes::SlotHash,
sysvar::clock::Clock,
};
use std::collections::VecDeque;
// Maximum number of votes to keep around
// Maximum number of votes to keep around, tightly coupled with epoch_schedule::MIN_SLOTS_PER_EPOCH
pub const MAX_LOCKOUT_HISTORY: usize = 31;
pub const INITIAL_LOCKOUT: usize = 2;

View File

@ -806,7 +806,7 @@ mod tests {
instructions,
);
let fee_calculator = FeeCalculator::new(10);
let fee_calculator = FeeCalculator::new(10, 0);
assert_eq!(fee_calculator.calculate_fee(tx.message()), 10);
let loaded_accounts =

View File

@ -2,13 +2,11 @@
//! programs. It offers a high-level API that signs transactions
//! on behalf of the caller, and a low-level API for when they have
//! already been signed and verified.
use crate::transaction_utils::OrderedIterator;
use crate::{
accounts::{Accounts, TransactionLoadResult},
accounts_db::{AccountStorageEntry, AccountsDBSerialize, AppendVecId, ErrorCounters},
accounts_index::Fork,
blockhash_queue::BlockhashQueue,
epoch_schedule::EpochSchedule,
message_processor::{MessageProcessor, ProcessInstruction},
rent_collector::RentCollector,
serde_utils::{
@ -19,6 +17,7 @@ use crate::{
storage_utils,
storage_utils::StorageAccounts,
transaction_batch::TransactionBatch,
transaction_utils::OrderedIterator,
};
use bincode::{deserialize_from, serialize_into};
use byteorder::{ByteOrder, LittleEndian};
@ -32,6 +31,7 @@ use solana_metrics::{
use solana_sdk::{
account::Account,
clock::{get_segment_from_slot, Epoch, Slot, MAX_RECENT_BLOCKHASHES},
epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator,
genesis_block::GenesisBlock,
hash::{hashv, Hash},
@ -39,20 +39,18 @@ use solana_sdk::{
native_loader,
pubkey::Pubkey,
signature::{Keypair, Signature},
system_transaction,
sysvar::{
clock, fees, rent, rewards,
slot_hashes::{self, SlotHashes},
stake_history,
},
slot_hashes::SlotHashes,
system_transaction, sysvar,
timing::duration_as_ns,
transaction::{Result, Transaction, TransactionError},
};
use std::collections::HashMap;
use std::io::{BufReader, Cursor, Error as IOError, Read};
use std::path::Path;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::{
collections::HashMap,
io::{BufReader, Cursor, Error as IOError, Read},
path::Path,
sync::atomic::{AtomicBool, AtomicU64, Ordering},
sync::{Arc, RwLock, RwLockReadGuard},
};
pub const SECONDS_PER_YEAR: f64 = (365.25 * 24.0 * 60.0 * 60.0);
@ -276,13 +274,14 @@ impl Bank {
// slot = 0 and genesis configuration
{
let stakes = bank.stakes.read().unwrap();
for epoch in 0..=bank.get_stakers_epoch(bank.slot) {
for epoch in 0..=bank.get_leader_schedule_epoch(bank.slot) {
bank.epoch_stakes.insert(epoch, stakes.clone());
}
bank.update_stake_history(None);
}
bank.update_clock();
bank.update_rent();
bank.update_epoch_schedule();
bank
}
@ -348,13 +347,13 @@ impl Bank {
("block_height", new.block_height, i64)
);
let stakers_epoch = epoch_schedule.get_stakers_epoch(slot);
let leader_schedule_epoch = epoch_schedule.get_leader_schedule_epoch(slot);
// update epoch_stakes cache
// if my parent didn't populate for this staker's epoch, we've
// crossed a boundary
if new.epoch_stakes.get(&stakers_epoch).is_none() {
if new.epoch_stakes.get(&leader_schedule_epoch).is_none() {
new.epoch_stakes
.insert(stakers_epoch, new.stakes.read().unwrap().clone());
.insert(leader_schedule_epoch, new.stakes.read().unwrap().clone());
}
new.ancestors.insert(new.slot(), 0);
@ -366,7 +365,6 @@ impl Bank {
new.update_stake_history(Some(parent.epoch()));
new.update_clock();
new.update_fees();
new.update_rent();
new
}
@ -426,37 +424,47 @@ impl Bank {
fn update_clock(&self) {
self.store_account(
&clock::id(),
&clock::new_account(
&sysvar::clock::id(),
&sysvar::clock::new_account(
1,
self.slot,
get_segment_from_slot(self.slot, self.slots_per_segment),
self.epoch_schedule.get_epoch(self.slot),
self.epoch_schedule.get_stakers_epoch(self.slot),
self.epoch_schedule.get_leader_schedule_epoch(self.slot),
),
);
}
fn update_slot_hashes(&self) {
let mut account = self
.get_account(&slot_hashes::id())
.unwrap_or_else(|| slot_hashes::create_account(1, &[]));
.get_account(&sysvar::slot_hashes::id())
.unwrap_or_else(|| sysvar::slot_hashes::create_account(1, &[]));
let mut slot_hashes = SlotHashes::from_account(&account).unwrap();
slot_hashes.add(self.slot(), self.hash());
slot_hashes.to_account(&mut account).unwrap();
self.store_account(&slot_hashes::id(), &account);
self.store_account(&sysvar::slot_hashes::id(), &account);
}
fn update_fees(&self) {
self.store_account(&fees::id(), &fees::create_account(1, &self.fee_calculator));
self.store_account(
&sysvar::fees::id(),
&sysvar::fees::create_account(1, &self.fee_calculator),
);
}
fn update_rent(&self) {
self.store_account(
&rent::id(),
&rent::create_account(1, &self.rent_collector.rent_calculator),
&sysvar::rent::id(),
&sysvar::rent::create_account(1, &self.rent_collector.rent_calculator),
);
}
fn update_epoch_schedule(&self) {
self.store_account(
&sysvar::epoch_schedule::id(),
&sysvar::epoch_schedule::create_account(1, &self.epoch_schedule),
);
}
@ -466,8 +474,8 @@ impl Bank {
}
// if I'm the first Bank in an epoch, ensure stake_history is updated
self.store_account(
&stake_history::id(),
&stake_history::create_account(1, self.stakes.read().unwrap().history()),
&sysvar::stake_history::id(),
&sysvar::stake_history::create_account(1, self.stakes.read().unwrap().history()),
);
}
@ -501,8 +509,8 @@ impl Bank {
storage_rewards / storage_points as f64,
);
self.store_account(
&rewards::id(),
&rewards::create_account(1, validator_point_value, storage_point_value),
&sysvar::rewards::id(),
&sysvar::rewards::create_account(1, validator_point_value, storage_point_value),
);
self.capitalization.fetch_add(
@ -518,10 +526,10 @@ impl Bank {
mut validator_point_value: f64,
mut storage_point_value: f64,
) -> (f64, f64) {
let rewards = rewards::Rewards::from_account(
let rewards = sysvar::rewards::Rewards::from_account(
&self
.get_account(&rewards::id())
.unwrap_or_else(|| rewards::create_account(1, 0.0, 0.0)),
.get_account(&sysvar::rewards::id())
.unwrap_or_else(|| sysvar::rewards::create_account(1, 0.0, 0.0)),
)
.unwrap_or_else(Default::default);
if !validator_point_value.is_normal() {
@ -651,11 +659,7 @@ impl Bank {
// make bank 0 votable
self.is_delta.store(true, Ordering::Relaxed);
self.epoch_schedule = EpochSchedule::new(
genesis_block.slots_per_epoch,
genesis_block.stakers_slot_offset,
genesis_block.epoch_warmup,
);
self.epoch_schedule = genesis_block.epoch_schedule;
self.inflation = genesis_block.inflation;
@ -1431,10 +1435,10 @@ impl Bank {
self.epoch_schedule.get_slots_in_epoch(epoch)
}
/// returns the epoch for which this bank's stakers_slot_offset and slot would
/// need to cache stakers
pub fn get_stakers_epoch(&self, slot: u64) -> u64 {
self.epoch_schedule.get_stakers_epoch(slot)
/// returns the epoch for which this bank's leader_schedule_slot_offset and slot would
/// need to cache leader_schedule
pub fn get_leader_schedule_epoch(&self, slot: u64) -> u64 {
self.epoch_schedule.get_leader_schedule_epoch(slot)
}
/// a bank-level cache of vote accounts
@ -1579,29 +1583,33 @@ impl Drop for Bank {
#[cfg(test)]
mod tests {
use super::*;
use crate::accounts_db::get_temp_accounts_paths;
use crate::accounts_db::tests::copy_append_vecs;
use crate::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
use crate::genesis_utils::{
create_genesis_block_with_leader, GenesisBlockInfo, BOOTSTRAP_LEADER_LAMPORTS,
use crate::{
accounts_db::get_temp_accounts_paths,
accounts_db::tests::copy_append_vecs,
genesis_utils::{
create_genesis_block_with_leader, GenesisBlockInfo, BOOTSTRAP_LEADER_LAMPORTS,
},
status_cache::MAX_CACHE_ENTRIES,
};
use crate::status_cache::MAX_CACHE_ENTRIES;
use bincode::{deserialize_from, serialize_into, serialized_size};
use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
use solana_sdk::genesis_block::create_genesis_block;
use solana_sdk::hash;
use solana_sdk::instruction::InstructionError;
use solana_sdk::poh_config::PohConfig;
use solana_sdk::rent_calculator::RentCalculator;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction;
use solana_sdk::system_transaction;
use solana_sdk::sysvar::{fees::Fees, rewards::Rewards};
use solana_sdk::{
clock::DEFAULT_TICKS_PER_SLOT,
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
genesis_block::create_genesis_block,
hash,
instruction::InstructionError,
poh_config::PohConfig,
rent_calculator::RentCalculator,
signature::{Keypair, KeypairUtil},
system_instruction, system_transaction,
sysvar::{fees::Fees, rewards::Rewards},
};
use solana_stake_api::stake_state::Stake;
use solana_vote_api::vote_instruction;
use solana_vote_api::vote_state::{VoteInit, VoteState, MAX_LOCKOUT_HISTORY};
use std::io::Cursor;
use std::time::Duration;
use solana_vote_api::{
vote_instruction,
vote_state::{VoteInit, VoteState, MAX_LOCKOUT_HISTORY},
};
use std::{io::Cursor, time::Duration};
use tempfile::TempDir;
#[test]
@ -1632,12 +1640,12 @@ mod tests {
dummy_leader_lamports /* 1 token goes to the vote account associated with dummy_leader_lamports */
);
let rent_account = bank.get_account(&rent::id()).unwrap();
let rent_sysvar = rent::Rent::from_account(&rent_account).unwrap();
let rent_account = bank.get_account(&sysvar::rent::id()).unwrap();
let rent = sysvar::rent::Rent::from_account(&rent_account).unwrap();
assert_eq!(rent_sysvar.rent_calculator.burn_percent, 5);
assert_eq!(rent_sysvar.rent_calculator.exemption_threshold, 1.2);
assert_eq!(rent_sysvar.rent_calculator.lamports_per_byte_year, 5);
assert_eq!(rent.rent_calculator.burn_percent, 5);
assert_eq!(rent.rent_calculator.exemption_threshold, 1.2);
assert_eq!(rent.rent_calculator.lamports_per_byte_year, 5);
}
#[test]
@ -1717,7 +1725,7 @@ mod tests {
let inflation = bank1.capitalization() - bank.capitalization();
let rewards = bank1
.get_account(&rewards::id())
.get_account(&sysvar::rewards::id())
.map(|account| Rewards::from_account(&account).unwrap())
.unwrap();
@ -2645,10 +2653,10 @@ mod tests {
// set this up weird, forces future generation, odd mod(), etc.
// this says: "vote_accounts for epoch X should be generated at slot index 3 in epoch X-2...
const SLOTS_PER_EPOCH: u64 = MINIMUM_SLOTS_PER_EPOCH as u64;
const STAKERS_SLOT_OFFSET: u64 = SLOTS_PER_EPOCH * 3 - 3;
genesis_block.slots_per_epoch = SLOTS_PER_EPOCH;
genesis_block.stakers_slot_offset = STAKERS_SLOT_OFFSET;
genesis_block.epoch_warmup = false; // allows me to do the normal division stuff below
const LEADER_SCHEDULE_SLOT_OFFSET: u64 = SLOTS_PER_EPOCH * 3 - 3;
// no warmup allows me to do the normal division stuff below
genesis_block.epoch_schedule =
EpochSchedule::custom(SLOTS_PER_EPOCH, LEADER_SCHEDULE_SLOT_OFFSET, false);
let parent = Arc::new(Bank::new(&genesis_block));
let mut leader_vote_stake: Vec<_> = parent
@ -2682,13 +2690,13 @@ mod tests {
let mut epoch = 1;
loop {
if epoch > STAKERS_SLOT_OFFSET / SLOTS_PER_EPOCH {
if epoch > LEADER_SCHEDULE_SLOT_OFFSET / SLOTS_PER_EPOCH {
break;
}
let vote_accounts = parent.epoch_vote_accounts(epoch);
assert!(vote_accounts.is_some());
// epoch_stakes are a snapshot at the stakers_slot_offset boundary
// epoch_stakes are a snapshot at the leader_schedule_slot_offset boundary
// in the prior epoch (0 in this case)
assert_eq!(
leader_stake.stake(0, None),
@ -2702,7 +2710,7 @@ mod tests {
let child = Bank::new_from_parent(
&parent,
&leader_pubkey,
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH),
SLOTS_PER_EPOCH - (LEADER_SCHEDULE_SLOT_OFFSET % SLOTS_PER_EPOCH),
);
assert!(child.epoch_vote_accounts(epoch).is_some());
@ -2721,7 +2729,7 @@ mod tests {
let child = Bank::new_from_parent(
&parent,
&leader_pubkey,
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH) + 1,
SLOTS_PER_EPOCH - (LEADER_SCHEDULE_SLOT_OFFSET % SLOTS_PER_EPOCH) + 1,
);
assert!(child.epoch_vote_accounts(epoch).is_some());
assert_eq!(
@ -2768,7 +2776,10 @@ mod tests {
bank.get_slots_in_epoch(2),
(MINIMUM_SLOTS_PER_EPOCH * 4) as u64
);
assert_eq!(bank.get_slots_in_epoch(5000), genesis_block.slots_per_epoch);
assert_eq!(
bank.get_slots_in_epoch(5000),
genesis_block.epoch_schedule.slots_per_epoch
);
}
#[test]
@ -2940,7 +2951,7 @@ mod tests {
genesis_block.fee_calculator.lamports_per_signature = 12345;
let bank = Arc::new(Bank::new(&genesis_block));
let fees_account = bank.get_account(&fees::id()).unwrap();
let fees_account = bank.get_account(&sysvar::fees::id()).unwrap();
let fees = Fees::from_account(&fees_account).unwrap();
assert_eq!(
bank.fee_calculator.lamports_per_signature,
@ -3037,7 +3048,10 @@ mod tests {
(0.0, 0.0)
);
bank.store_account(&rewards::id(), &rewards::create_account(1, 1.0, 1.0));
bank.store_account(
&sysvar::rewards::id(),
&sysvar::rewards::create_account(1, 1.0, 1.0),
);
// check that point values are the previous value if current values are not normal
assert_eq!(
bank.check_point_values(std::f64::INFINITY, std::f64::NAN),

View File

@ -72,7 +72,7 @@ pub fn create_genesis_block_with_leader(
solana_vote_program!(),
solana_stake_program!(),
])
.fee_calculator(FeeCalculator::new(0)); // most tests don't want fees
.fee_calculator(FeeCalculator::new(0, 0)); // most tests don't want fees
builder = solana_stake_api::genesis(builder);
builder = solana_storage_api::rewards_pools::genesis(builder);

View File

@ -6,7 +6,6 @@ pub mod bank;
pub mod bank_client;
mod blockhash_queue;
pub mod bloom;
pub mod epoch_schedule;
pub mod genesis_utils;
pub mod loader_utils;
pub mod message_processor;

View File

@ -1,6 +1,7 @@
//! calculate and collect rent from Accounts
use crate::epoch_schedule::EpochSchedule;
use solana_sdk::{account::Account, clock::Epoch, rent_calculator::RentCalculator};
use solana_sdk::{
account::Account, clock::Epoch, epoch_schedule::EpochSchedule, rent_calculator::RentCalculator,
};
#[derive(Default, Serialize, Deserialize, Clone)]
pub struct RentCollector {

View File

@ -6,11 +6,10 @@
maxOpenFds=65000
if [[ $(ulimit -n) -lt $maxOpenFds ]]; then
ulimit -n $maxOpenFds || {
ulimit -n $maxOpenFds 2>/dev/null || {
echo "Error: nofiles too small: $(ulimit -n). Failed to run \"ulimit -n $maxOpenFds\"";
if [[ $(uname) = Darwin ]]; then
echo "Try running |sudo launchctl limit maxfiles 65536 200000| first"
fi
}
fi

View File

@ -12,9 +12,7 @@ fi
echo "Building $1"
set -e
pushd "$(dirname "$0")"
bpf_sdk="$PWD/.."
popd
bpf_sdk=$(cd "$(dirname "$0")/.." && pwd)
# Ensure the sdk is installed
"$bpf_sdk"/scripts/install.sh

View File

@ -17,6 +17,7 @@ pub const DEFAULT_SLOTS_PER_SEGMENT: u64 = 1024;
// 4 times longer than the max_lockout to allow enough time for PoRep (128 slots)
pub const DEFAULT_SLOTS_PER_TURN: u64 = 32 * 4;
// leader schedule is governed by this
pub const NUM_CONSECUTIVE_LEADER_SLOTS: u64 = 4;
/// The time window of recent block hash values that the bank will track the signatures

View File

@ -1,24 +1,51 @@
use solana_vote_api::vote_state::MAX_LOCKOUT_HISTORY;
//! configuration for epochs, slots
pub const MINIMUM_SLOTS_PER_EPOCH: u64 = (MAX_LOCKOUT_HISTORY + 1) as u64;
/// 1 Epoch = 400 * 8192 ms ~= 55 minutes
pub use crate::clock::{Epoch, Slot, DEFAULT_SLOTS_PER_EPOCH};
#[derive(Default, Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
/// The number of slots before an epoch starts to calculate the leader schedule.
/// Default is an entire epoch, i.e. leader schedule for epoch X is calculated at
/// the beginning of epoch X - 1.
pub const DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET: u64 = DEFAULT_SLOTS_PER_EPOCH;
/// based on MAX_LOCKOUT_HISTORY from vote_api
pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub struct EpochSchedule {
/// The maximum number of slots in each epoch.
pub slots_per_epoch: u64,
/// A number of slots before slot_index 0. Used to calculate finalized staked nodes.
pub stakers_slot_offset: u64,
/// A number of slots before beginning of an epoch to calculate
/// a leader schedule for that epoch
pub leader_schedule_slot_offset: u64,
/// whether epochs start short and grow
pub warmup: bool,
/// basically: log2(slots_per_epoch) - log2(MINIMUM_SLOT_LEN)
pub first_normal_epoch: u64,
pub first_normal_epoch: Epoch,
/// basically: 2.pow(first_normal_epoch) - MINIMUM_SLOT_LEN
pub first_normal_slot: u64,
pub first_normal_slot: Slot,
}
impl Default for EpochSchedule {
fn default() -> Self {
Self::custom(
DEFAULT_SLOTS_PER_EPOCH,
DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET,
true,
)
}
}
impl EpochSchedule {
pub fn new(slots_per_epoch: u64, stakers_slot_offset: u64, warmup: bool) -> Self {
pub fn new(slots_per_epoch: u64) -> Self {
Self::custom(slots_per_epoch, slots_per_epoch, true)
}
pub fn custom(slots_per_epoch: u64, leader_schedule_slot_offset: u64, warmup: bool) -> Self {
assert!(slots_per_epoch >= MINIMUM_SLOTS_PER_EPOCH as u64);
let (first_normal_epoch, first_normal_slot) = if warmup {
let next_power_of_two = slots_per_epoch.next_power_of_two();
@ -35,7 +62,8 @@ impl EpochSchedule {
};
EpochSchedule {
slots_per_epoch,
stakers_slot_offset,
leader_schedule_slot_offset,
warmup,
first_normal_epoch,
first_normal_slot,
}
@ -52,13 +80,14 @@ impl EpochSchedule {
/// get the epoch for which the given slot should save off
/// information about stakers
pub fn get_stakers_epoch(&self, slot: u64) -> u64 {
pub fn get_leader_schedule_epoch(&self, slot: u64) -> u64 {
if slot < self.first_normal_slot {
// until we get to normal slots, behave as if stakers_slot_offset == slots_per_epoch
// until we get to normal slots, behave as if leader_schedule_slot_offset == slots_per_epoch
self.get_epoch_and_slot_index(slot).0 + 1
} else {
self.first_normal_epoch
+ (slot - self.first_normal_slot + self.stakers_slot_offset) / self.slots_per_epoch
+ (slot - self.first_normal_slot + self.leader_schedule_slot_offset)
/ self.slots_per_epoch
}
}
@ -114,7 +143,7 @@ mod tests {
// test values between MINIMUM_SLOT_LEN and MINIMUM_SLOT_LEN * 16, should cover a good mix
for slots_per_epoch in MINIMUM_SLOTS_PER_EPOCH..=MINIMUM_SLOTS_PER_EPOCH * 16 {
let epoch_schedule = EpochSchedule::new(slots_per_epoch, slots_per_epoch / 2, true);
let epoch_schedule = EpochSchedule::custom(slots_per_epoch, slots_per_epoch / 2, true);
assert_eq!(epoch_schedule.get_first_slot_in_epoch(0), 0);
assert_eq!(
@ -122,17 +151,17 @@ mod tests {
MINIMUM_SLOTS_PER_EPOCH - 1
);
let mut last_stakers = 0;
let mut last_leader_schedule = 0;
let mut last_epoch = 0;
let mut last_slots_in_epoch = MINIMUM_SLOTS_PER_EPOCH;
for slot in 0..(2 * slots_per_epoch) {
// verify that stakers_epoch is continuous over the warmup
// verify that leader_schedule_epoch is continuous over the warmup
// and into the first normal epoch
let stakers = epoch_schedule.get_stakers_epoch(slot);
if stakers != last_stakers {
assert_eq!(stakers, last_stakers + 1);
last_stakers = stakers;
let leader_schedule = epoch_schedule.get_leader_schedule_epoch(slot);
if leader_schedule != last_leader_schedule {
assert_eq!(leader_schedule, last_leader_schedule + 1);
last_leader_schedule = leader_schedule;
}
let (epoch, offset) = epoch_schedule.get_epoch_and_slot_index(slot);
@ -160,7 +189,7 @@ mod tests {
}
// assert that these changed ;)
assert!(last_stakers != 0); // t
assert!(last_leader_schedule != 0); // t
assert!(last_epoch != 0);
// assert that we got to "normal" mode
assert!(last_slots_in_epoch == slots_per_epoch);

View File

@ -45,11 +45,11 @@ impl Default for FeeCalculator {
}
impl FeeCalculator {
pub fn new(target_lamports_per_signature: u64) -> Self {
pub fn new(target_lamports_per_signature: u64, target_signatures_per_slot: usize) -> Self {
let base_fee_calculator = Self {
target_lamports_per_signature,
lamports_per_signature: target_lamports_per_signature,
target_signatures_per_slot: 0,
target_signatures_per_slot,
..FeeCalculator::default()
};
@ -160,20 +160,20 @@ mod tests {
assert_eq!(FeeCalculator::default().calculate_fee(&message), 0);
// No signature, no fee.
assert_eq!(FeeCalculator::new(1).calculate_fee(&message), 0);
assert_eq!(FeeCalculator::new(1, 0).calculate_fee(&message), 0);
// One signature, a fee.
let pubkey0 = Pubkey::new(&[0; 32]);
let pubkey1 = Pubkey::new(&[1; 32]);
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
let message = Message::new(vec![ix0]);
assert_eq!(FeeCalculator::new(2).calculate_fee(&message), 2);
assert_eq!(FeeCalculator::new(2, 0).calculate_fee(&message), 2);
// Two signatures, double the fee.
let ix0 = system_instruction::transfer(&pubkey0, &pubkey1, 1);
let ix1 = system_instruction::transfer(&pubkey1, &pubkey0, 1);
let message = Message::new(vec![ix0, ix1]);
assert_eq!(FeeCalculator::new(2).calculate_fee(&message), 4);
assert_eq!(FeeCalculator::new(2, 0).calculate_fee(&message), 4);
}
#[test]

View File

@ -1,35 +1,38 @@
//! The `genesis_block` module is a library for generating the chain's genesis block.
use crate::account::Account;
use crate::clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT};
use crate::fee_calculator::FeeCalculator;
use crate::hash::{hash, Hash};
use crate::inflation::Inflation;
use crate::poh_config::PohConfig;
use crate::pubkey::Pubkey;
use crate::rent_calculator::RentCalculator;
use crate::signature::{Keypair, KeypairUtil};
use crate::system_program::{self, solana_system_program};
use crate::{
account::Account,
clock::{DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator,
hash::{hash, Hash},
inflation::Inflation,
poh_config::PohConfig,
pubkey::Pubkey,
rent_calculator::RentCalculator,
signature::{Keypair, KeypairUtil},
system_program::{self, solana_system_program},
};
use bincode::{deserialize, serialize};
use memmap::Mmap;
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::{
fs::{File, OpenOptions},
io::Write,
path::Path,
};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GenesisBlock {
pub accounts: Vec<(Pubkey, Account)>,
pub native_instruction_processors: Vec<(String, Pubkey)>,
pub rewards_pools: Vec<(Pubkey, Account)>,
pub slots_per_epoch: u64,
pub stakers_slot_offset: u64,
pub epoch_warmup: bool,
pub ticks_per_slot: u64,
pub slots_per_segment: u64,
pub poh_config: PohConfig,
pub fee_calculator: FeeCalculator,
pub rent_calculator: RentCalculator,
pub inflation: Inflation,
pub epoch_schedule: EpochSchedule,
}
// useful for basic tests
@ -53,15 +56,13 @@ impl Default for GenesisBlock {
accounts: Vec::new(),
native_instruction_processors: Vec::new(),
rewards_pools: Vec::new(),
epoch_warmup: true,
slots_per_epoch: DEFAULT_SLOTS_PER_EPOCH,
stakers_slot_offset: DEFAULT_SLOTS_PER_EPOCH,
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
slots_per_segment: DEFAULT_SLOTS_PER_SEGMENT,
poh_config: PohConfig::default(),
inflation: Inflation::default(),
fee_calculator: FeeCalculator::default(),
rent_calculator: RentCalculator::default(),
epoch_schedule: EpochSchedule::default(),
}
}
}
@ -69,7 +70,6 @@ impl Default for GenesisBlock {
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Builder {
genesis_block: GenesisBlock,
already_have_stakers_slot_offset: bool,
}
impl Builder {
@ -114,21 +114,8 @@ impl Builder {
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;
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 {

View File

@ -2,6 +2,7 @@ pub mod account;
pub mod account_utils;
pub mod bpf_loader;
pub mod clock;
pub mod epoch_schedule;
pub mod fee_calculator;
pub mod hash;
pub mod inflation;
@ -17,6 +18,7 @@ pub mod pubkey;
pub mod rent_calculator;
pub mod rpc_port;
pub mod short_vec;
pub mod slot_hashes;
pub mod system_instruction;
pub mod system_program;
pub mod sysvar;

77
sdk/src/slot_hashes.rs Normal file
View File

@ -0,0 +1,77 @@
//! named accounts for synthesized data accounts for bank state, etc.
//!
//! this account carries the Bank's most recent blockhashes for some N parents
//!
use crate::hash::Hash;
use std::ops::Deref;
pub const MAX_SLOT_HASHES: usize = 512; // 512 slots to get your vote in
pub use crate::clock::Slot;
pub type SlotHash = (Slot, Hash);
#[repr(C)]
#[derive(Serialize, Deserialize, PartialEq, Debug, Default)]
pub struct SlotHashes(Vec<SlotHash>);
impl SlotHashes {
pub fn add(&mut self, slot: Slot, hash: Hash) {
match self.binary_search_by(|probe| slot.cmp(&probe.0)) {
Ok(index) => (self.0)[index] = (slot, hash),
Err(index) => (self.0).insert(index, (slot, hash)),
}
(self.0).truncate(MAX_SLOT_HASHES);
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn get(&self, slot: &Slot) -> Option<&Hash> {
self.binary_search_by(|probe| slot.cmp(&probe.0))
.ok()
.map(|index| &self[index].1)
}
pub fn new(slot_hashes: &[SlotHash]) -> Self {
let mut slot_hashes = slot_hashes.to_vec();
slot_hashes.sort_by(|a, b| b.0.cmp(&a.0)); // reverse order
Self(slot_hashes)
}
}
impl Deref for SlotHashes {
type Target = Vec<SlotHash>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hash::hash;
#[test]
fn test() {
let mut slot_hashes = SlotHashes::new(&[(1, Hash::default()), (3, Hash::default())]);
slot_hashes.add(2, Hash::default());
assert_eq!(
slot_hashes,
SlotHashes(vec![
(3, Hash::default()),
(2, Hash::default()),
(1, Hash::default()),
])
);
let mut slot_hashes = SlotHashes::new(&[]);
for i in 0..MAX_SLOT_HASHES + 1 {
slot_hashes.add(
i as u64,
hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]),
);
}
for i in 0..MAX_SLOT_HASHES {
assert_eq!(slot_hashes[i].0, (MAX_SLOT_HASHES - i) as u64);
}
assert_eq!(slot_hashes.len(), MAX_SLOT_HASHES);
}
}

View File

@ -0,0 +1,57 @@
//! This account contains the current cluster rent
//!
use crate::{
account::{Account, KeyedAccount},
account_info::AccountInfo,
epoch_schedule::EpochSchedule,
instruction::InstructionError,
sysvar,
};
/// epoch_schedule account pubkey
const ID: [u8; 32] = [
6, 167, 213, 23, 24, 220, 63, 238, 2, 211, 228, 127, 1, 0, 248, 176, 84, 247, 148, 46, 96, 89,
30, 63, 80, 135, 25, 168, 5, 0, 0, 0,
];
crate::solana_name_id!(ID, "SysvarEpochSchedu1e111111111111111111111111");
impl EpochSchedule {
pub fn deserialize(account: &Account) -> Result<Self, bincode::Error> {
account.deserialize_data()
}
pub fn from_account(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to_account(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn from_account_info(account: &AccountInfo) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to_account_info(&self, account: &mut AccountInfo) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn from_keyed_account(account: &KeyedAccount) -> Result<EpochSchedule, InstructionError> {
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
EpochSchedule::from_account(account.account).ok_or(InstructionError::InvalidArgument)
}
}
pub fn create_account(lamports: u64, epoch_schedule: &EpochSchedule) -> Account {
Account::new_data(lamports, epoch_schedule, &sysvar::id()).unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_account() {
let account = create_account(42, &EpochSchedule::default());
let epoch_schedule = EpochSchedule::from_account(&account).unwrap();
assert_eq!(epoch_schedule, EpochSchedule::default());
}
}

View File

@ -3,6 +3,7 @@
use crate::pubkey::Pubkey;
pub mod clock;
pub mod epoch_schedule;
pub mod fees;
pub mod rent;
pub mod rewards;

View File

@ -1,9 +1,12 @@
//! This account contains the current cluster rent
//!
use crate::account::Account;
use crate::account_info::AccountInfo;
use crate::rent_calculator::RentCalculator;
use crate::sysvar;
use crate::{
account::{Account, KeyedAccount},
account_info::AccountInfo,
instruction::InstructionError,
rent_calculator::RentCalculator,
sysvar,
};
use bincode::serialized_size;
/// rent account pubkey
@ -49,9 +52,6 @@ pub fn create_account(lamports: u64, rent_calculator: &RentCalculator) -> Accoun
.unwrap()
}
use crate::account::KeyedAccount;
use crate::instruction::InstructionError;
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Rent, InstructionError> {
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);

View File

@ -58,7 +58,6 @@ use crate::account::KeyedAccount;
use crate::instruction::InstructionError;
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Rewards, InstructionError> {
if !check_id(account.unsigned_key()) {
dbg!(account.unsigned_key());
return Err(InstructionError::InvalidArgument);
}
Rewards::from_account(account.account).ok_or(InstructionError::InvalidAccountData)

View File

@ -2,14 +2,9 @@
//!
//! this account carries the Bank's most recent blockhashes for some N parents
//!
use crate::account::Account;
use crate::account_info::AccountInfo;
use crate::hash::Hash;
use crate::sysvar;
pub use crate::slot_hashes::{SlotHash, SlotHashes};
use crate::{account::Account, account_info::AccountInfo, sysvar};
use bincode::serialized_size;
use std::ops::Deref;
pub use crate::clock::Slot;
const ID: [u8; 32] = [
6, 167, 213, 23, 25, 47, 10, 175, 198, 242, 101, 227, 251, 119, 204, 122, 218, 130, 197, 41,
@ -20,11 +15,6 @@ crate::solana_name_id!(ID, "SysvarS1otHashes111111111111111111111111111");
pub const MAX_SLOT_HASHES: usize = 512; // 512 slots to get your vote in
pub type SlotHash = (Slot, Hash);
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct SlotHashes(Vec<SlotHash>);
impl SlotHashes {
pub fn from_account(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
@ -39,30 +29,7 @@ impl SlotHashes {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&SlotHashes(vec![(0, Hash::default()); MAX_SLOT_HASHES])).unwrap() as usize
}
pub fn add(&mut self, slot: Slot, hash: Hash) {
match self.binary_search_by(|probe| slot.cmp(&probe.0)) {
Ok(index) => (self.0)[index] = (slot, hash),
Err(index) => (self.0).insert(index, (slot, hash)),
}
(self.0).truncate(MAX_SLOT_HASHES);
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn get(&self, slot: &Slot) -> Option<&Hash> {
self.binary_search_by(|probe| slot.cmp(&probe.0))
.ok()
.map(|index| &self[index].1)
}
pub fn new(slot_hashes: &[SlotHash]) -> Self {
Self(slot_hashes.to_vec())
}
}
impl Deref for SlotHashes {
type Target = Vec<SlotHash>;
fn deref(&self) -> &Self::Target {
&self.0
serialized_size(&SlotHashes::new(&[SlotHash::default(); MAX_SLOT_HASHES])).unwrap() as usize
}
}
@ -86,7 +53,6 @@ pub fn from_keyed_account(account: &KeyedAccount) -> Result<SlotHashes, Instruct
#[cfg(test)]
mod tests {
use super::*;
use crate::hash::hash;
#[test]
fn test_create_account() {
@ -94,18 +60,6 @@ mod tests {
let account = create_account(lamports, &[]);
assert_eq!(account.data.len(), SlotHashes::size_of());
let slot_hashes = SlotHashes::from_account(&account);
assert_eq!(slot_hashes, Some(SlotHashes(vec![])));
let mut slot_hashes = slot_hashes.unwrap();
for i in 0..MAX_SLOT_HASHES + 1 {
slot_hashes.add(
i as u64,
hash(&[(i >> 24) as u8, (i >> 16) as u8, (i >> 8) as u8, i as u8]),
);
}
for i in 0..MAX_SLOT_HASHES {
assert_eq!(slot_hashes[i].0, (MAX_SLOT_HASHES - i) as u64);
}
assert_eq!(slot_hashes.len(), MAX_SLOT_HASHES);
assert_eq!(slot_hashes, Some(SlotHashes::default()));
}
}

View File

@ -24,6 +24,7 @@ pub struct StakeHistoryEntry {
pub deactivating: u64, // requested to be cooled down, not fully deactivated yet
}
#[repr(C)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
pub struct StakeHistory(Vec<(Epoch, StakeHistoryEntry)>);