add epoch_schedule sysvar (#6256)
* add epoch_schedule sysvar * book sheesh!
This commit is contained in:
parent
f2ee01ace3
commit
7cf90766a3
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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%/}"
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
use crate::pubkey::Pubkey;
|
||||
|
||||
pub mod clock;
|
||||
pub mod epoch_schedule;
|
||||
pub mod fees;
|
||||
pub mod rent;
|
||||
pub mod rewards;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)>);
|
||||
|
||||
|
|
Loading…
Reference in New Issue