@@ -1,7 +1,6 @@
|
||||
use crate::cluster::{Cluster, ClusterValidatorInfo, ValidatorInfo};
|
||||
use itertools::izip;
|
||||
use log::*;
|
||||
use solana_archiver_lib::archiver::Archiver;
|
||||
use solana_client::thin_client::{create_client, ThinClient};
|
||||
use solana_core::{
|
||||
cluster_info::{Node, VALIDATOR_PORT_RANGE},
|
||||
@@ -15,60 +14,35 @@ use solana_ledger::{
|
||||
};
|
||||
use solana_sdk::{
|
||||
client::SyncClient,
|
||||
clock::{DEFAULT_DEV_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
|
||||
clock::{DEFAULT_DEV_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT},
|
||||
commitment_config::CommitmentConfig,
|
||||
epoch_schedule::EpochSchedule,
|
||||
genesis_config::{GenesisConfig, OperatingMode},
|
||||
message::Message,
|
||||
poh_config::PohConfig,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
transaction::Transaction,
|
||||
transport::Result as TransportResult,
|
||||
};
|
||||
use solana_stake_program::{
|
||||
config as stake_config, stake_instruction,
|
||||
stake_state::{Authorized, Lockup, StakeState},
|
||||
};
|
||||
use solana_storage_program::{
|
||||
storage_contract,
|
||||
storage_instruction::{self, StorageAccountType},
|
||||
};
|
||||
use solana_vote_program::{
|
||||
vote_instruction,
|
||||
vote_state::{VoteInit, VoteState},
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::remove_dir_all,
|
||||
io::{Error, ErrorKind, Result},
|
||||
iter,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub struct ArchiverInfo {
|
||||
pub archiver_storage_pubkey: Pubkey,
|
||||
pub ledger_path: PathBuf,
|
||||
}
|
||||
|
||||
impl ArchiverInfo {
|
||||
fn new(storage_pubkey: Pubkey, ledger_path: PathBuf) -> Self {
|
||||
Self {
|
||||
archiver_storage_pubkey: storage_pubkey,
|
||||
ledger_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClusterConfig {
|
||||
/// The validator config that should be applied to every node in the cluster
|
||||
pub validator_configs: Vec<ValidatorConfig>,
|
||||
/// Number of archivers in the cluster
|
||||
/// Note- archivers will timeout if ticks_per_slot is much larger than the default 8
|
||||
pub num_archivers: usize,
|
||||
/// Number of nodes that are unstaked and not voting (a.k.a listening)
|
||||
pub num_listeners: u64,
|
||||
/// The specific pubkeys of each node if specified
|
||||
@@ -79,7 +53,6 @@ pub struct ClusterConfig {
|
||||
pub cluster_lamports: u64,
|
||||
pub ticks_per_slot: u64,
|
||||
pub slots_per_epoch: u64,
|
||||
pub slots_per_segment: u64,
|
||||
pub stakers_slot_offset: u64,
|
||||
pub native_instruction_processors: Vec<(String, Pubkey)>,
|
||||
pub operating_mode: OperatingMode,
|
||||
@@ -90,14 +63,12 @@ impl Default for ClusterConfig {
|
||||
fn default() -> Self {
|
||||
ClusterConfig {
|
||||
validator_configs: vec![],
|
||||
num_archivers: 0,
|
||||
num_listeners: 0,
|
||||
validator_keys: None,
|
||||
node_stakes: vec![],
|
||||
cluster_lamports: 0,
|
||||
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
|
||||
slots_per_epoch: DEFAULT_DEV_SLOTS_PER_EPOCH,
|
||||
slots_per_segment: DEFAULT_SLOTS_PER_SEGMENT,
|
||||
stakers_slot_offset: DEFAULT_DEV_SLOTS_PER_EPOCH,
|
||||
native_instruction_processors: vec![],
|
||||
operating_mode: OperatingMode::Development,
|
||||
@@ -113,8 +84,6 @@ pub struct LocalCluster {
|
||||
pub entry_point_info: ContactInfo,
|
||||
pub validators: HashMap<Pubkey, ClusterValidatorInfo>,
|
||||
pub genesis_config: GenesisConfig,
|
||||
archivers: Vec<Archiver>,
|
||||
pub archiver_infos: HashMap<Pubkey, ArchiverInfo>,
|
||||
}
|
||||
|
||||
impl LocalCluster {
|
||||
@@ -159,7 +128,6 @@ impl LocalCluster {
|
||||
config.node_stakes[0],
|
||||
);
|
||||
genesis_config.ticks_per_slot = config.ticks_per_slot;
|
||||
genesis_config.slots_per_segment = config.slots_per_segment;
|
||||
genesis_config.epoch_schedule =
|
||||
EpochSchedule::custom(config.slots_per_epoch, config.stakers_slot_offset, true);
|
||||
genesis_config.operating_mode = config.operating_mode;
|
||||
@@ -171,11 +139,7 @@ impl LocalCluster {
|
||||
solana_genesis_programs::get_programs(genesis_config.operating_mode, 0)
|
||||
.unwrap_or_else(|| vec![])
|
||||
}
|
||||
OperatingMode::Development => {
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_storage_program!());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
genesis_config.inflation =
|
||||
@@ -185,12 +149,6 @@ impl LocalCluster {
|
||||
.native_instruction_processors
|
||||
.extend_from_slice(&config.native_instruction_processors);
|
||||
|
||||
let storage_keypair = Keypair::new();
|
||||
genesis_config.add_account(
|
||||
storage_keypair.pubkey(),
|
||||
storage_contract::create_validator_storage_account(leader_pubkey, 1),
|
||||
);
|
||||
|
||||
// Replace staking config
|
||||
genesis_config.add_account(
|
||||
stake_config::id(),
|
||||
@@ -205,7 +163,6 @@ impl LocalCluster {
|
||||
|
||||
let (leader_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config);
|
||||
let leader_contact_info = leader_node.info.clone();
|
||||
let leader_storage_keypair = Arc::new(storage_keypair);
|
||||
let leader_voting_keypair = Arc::new(voting_keypair);
|
||||
let mut leader_config = config.validator_configs[0].clone();
|
||||
leader_config.rpc_ports = Some((
|
||||
@@ -218,7 +175,6 @@ impl LocalCluster {
|
||||
&leader_ledger_path,
|
||||
&leader_voting_keypair.pubkey(),
|
||||
vec![leader_voting_keypair.clone()],
|
||||
&leader_storage_keypair,
|
||||
None,
|
||||
true,
|
||||
&leader_config,
|
||||
@@ -229,7 +185,6 @@ impl LocalCluster {
|
||||
let leader_info = ValidatorInfo {
|
||||
keypair: leader_keypair.clone(),
|
||||
voting_keypair: leader_voting_keypair,
|
||||
storage_keypair: leader_storage_keypair,
|
||||
ledger_path: leader_ledger_path,
|
||||
contact_info: leader_contact_info.clone(),
|
||||
};
|
||||
@@ -246,9 +201,7 @@ impl LocalCluster {
|
||||
funding_keypair: mint_keypair,
|
||||
entry_point_info: leader_contact_info,
|
||||
validators,
|
||||
archivers: vec![],
|
||||
genesis_config,
|
||||
archiver_infos: HashMap::new(),
|
||||
};
|
||||
|
||||
for (stake, validator_config, key) in izip!(
|
||||
@@ -273,15 +226,7 @@ impl LocalCluster {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
for _ in 0..config.num_archivers {
|
||||
cluster.add_archiver();
|
||||
}
|
||||
|
||||
discover_cluster(
|
||||
&cluster.entry_point_info.gossip,
|
||||
config.node_stakes.len() + config.num_archivers as usize,
|
||||
)
|
||||
.unwrap();
|
||||
discover_cluster(&cluster.entry_point_info.gossip, config.node_stakes.len()).unwrap();
|
||||
|
||||
cluster
|
||||
}
|
||||
@@ -301,10 +246,6 @@ impl LocalCluster {
|
||||
v.join().expect("Validator join failed");
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(archiver) = self.archivers.pop() {
|
||||
archiver.close();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_validator(
|
||||
@@ -320,7 +261,6 @@ impl LocalCluster {
|
||||
|
||||
// Must have enough tokens to fund vote account and set delegate
|
||||
let voting_keypair = Keypair::new();
|
||||
let storage_keypair = Arc::new(Keypair::new());
|
||||
let validator_pubkey = validator_keypair.pubkey();
|
||||
let validator_node = Node::new_localhost_with_pubkey(&validator_keypair.pubkey());
|
||||
let contact_info = validator_node.info.clone();
|
||||
@@ -330,7 +270,7 @@ impl LocalCluster {
|
||||
// setup as a listener
|
||||
info!("listener {} ", validator_pubkey,);
|
||||
} else {
|
||||
// Give the validator some lamports to setup vote and storage accounts
|
||||
// Give the validator some lamports to setup vote accounts
|
||||
let validator_balance = Self::transfer_with_client(
|
||||
&client,
|
||||
&self.funding_keypair,
|
||||
@@ -349,9 +289,6 @@ impl LocalCluster {
|
||||
stake,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Self::setup_storage_account(&client, &storage_keypair, &validator_keypair, false)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let mut config = validator_config.clone();
|
||||
@@ -366,7 +303,6 @@ impl LocalCluster {
|
||||
&ledger_path,
|
||||
&voting_keypair.pubkey(),
|
||||
vec![voting_keypair.clone()],
|
||||
&storage_keypair,
|
||||
Some(&self.entry_point_info),
|
||||
true,
|
||||
&config,
|
||||
@@ -377,7 +313,6 @@ impl LocalCluster {
|
||||
ValidatorInfo {
|
||||
keypair: validator_keypair,
|
||||
voting_keypair,
|
||||
storage_keypair,
|
||||
ledger_path,
|
||||
contact_info,
|
||||
},
|
||||
@@ -389,56 +324,8 @@ impl LocalCluster {
|
||||
validator_pubkey
|
||||
}
|
||||
|
||||
fn add_archiver(&mut self) {
|
||||
let archiver_keypair = Arc::new(Keypair::new());
|
||||
let archiver_pubkey = archiver_keypair.pubkey();
|
||||
let storage_keypair = Arc::new(Keypair::new());
|
||||
let storage_pubkey = storage_keypair.pubkey();
|
||||
let client = create_client(
|
||||
self.entry_point_info.client_facing_addr(),
|
||||
VALIDATOR_PORT_RANGE,
|
||||
);
|
||||
|
||||
// Give the archiver some lamports to setup its storage accounts
|
||||
Self::transfer_with_client(
|
||||
&client,
|
||||
&self.funding_keypair,
|
||||
&archiver_keypair.pubkey(),
|
||||
42,
|
||||
);
|
||||
let archiver_node = Node::new_localhost_archiver(&archiver_pubkey);
|
||||
|
||||
Self::setup_storage_account(&client, &storage_keypair, &archiver_keypair, true).unwrap();
|
||||
|
||||
let (archiver_ledger_path, _blockhash) = create_new_tmp_ledger!(&self.genesis_config);
|
||||
let archiver = Archiver::new(
|
||||
&archiver_ledger_path,
|
||||
archiver_node,
|
||||
self.entry_point_info.clone(),
|
||||
archiver_keypair,
|
||||
storage_keypair,
|
||||
CommitmentConfig::recent(),
|
||||
)
|
||||
.unwrap_or_else(|err| panic!("Archiver::new() failed: {:?}", err));
|
||||
|
||||
self.archivers.push(archiver);
|
||||
self.archiver_infos.insert(
|
||||
archiver_pubkey,
|
||||
ArchiverInfo::new(storage_pubkey, archiver_ledger_path),
|
||||
);
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
self.close_preserve_ledgers();
|
||||
for ledger_path in self
|
||||
.validators
|
||||
.values()
|
||||
.map(|f| &f.info.ledger_path)
|
||||
.chain(self.archiver_infos.values().map(|info| &info.ledger_path))
|
||||
{
|
||||
remove_dir_all(&ledger_path)
|
||||
.unwrap_or_else(|_| panic!("Unable to remove {:?}", ledger_path));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transfer(&self, source_keypair: &Keypair, dest_pubkey: &Pubkey, lamports: u64) -> u64 {
|
||||
@@ -601,40 +488,6 @@ impl LocalCluster {
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the storage account for validators/archivers and assumes the funder is the owner
|
||||
fn setup_storage_account(
|
||||
client: &ThinClient,
|
||||
storage_keypair: &Keypair,
|
||||
from_keypair: &Arc<Keypair>,
|
||||
archiver: bool,
|
||||
) -> TransportResult<()> {
|
||||
let storage_account_type = if archiver {
|
||||
StorageAccountType::Archiver
|
||||
} else {
|
||||
StorageAccountType::Validator
|
||||
};
|
||||
let message = Message::new_with_payer(
|
||||
&storage_instruction::create_storage_account(
|
||||
&from_keypair.pubkey(),
|
||||
&from_keypair.pubkey(),
|
||||
&storage_keypair.pubkey(),
|
||||
1,
|
||||
storage_account_type,
|
||||
),
|
||||
Some(&from_keypair.pubkey()),
|
||||
);
|
||||
|
||||
let signer_keys = vec![from_keypair.as_ref(), &storage_keypair];
|
||||
let blockhash = client
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.0;
|
||||
let mut transaction = Transaction::new(&signer_keys, message, blockhash);
|
||||
client
|
||||
.retry_transfer(&from_keypair, &mut transaction, 10)
|
||||
.map(|_signature| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl Cluster for LocalCluster {
|
||||
@@ -686,7 +539,6 @@ impl Cluster for LocalCluster {
|
||||
&validator_info.ledger_path,
|
||||
&validator_info.voting_keypair.pubkey(),
|
||||
vec![validator_info.voting_keypair.clone()],
|
||||
&validator_info.storage_keypair,
|
||||
entry_point_info,
|
||||
true,
|
||||
&cluster_validator_info.config,
|
||||
@@ -716,7 +568,6 @@ impl Drop for LocalCluster {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use solana_core::storage_stage::SLOTS_PER_TURN_TEST;
|
||||
use solana_sdk::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
|
||||
|
||||
#[test]
|
||||
@@ -725,7 +576,6 @@ mod test {
|
||||
let num_nodes = 1;
|
||||
let cluster = LocalCluster::new_with_equal_stakes(num_nodes, 100, 3);
|
||||
assert_eq!(cluster.validators.len(), num_nodes);
|
||||
assert_eq!(cluster.archivers.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -733,12 +583,9 @@ mod test {
|
||||
solana_logger::setup();
|
||||
let mut validator_config = ValidatorConfig::default();
|
||||
validator_config.rpc_config.enable_validator_exit = true;
|
||||
validator_config.storage_slots_per_turn = SLOTS_PER_TURN_TEST;
|
||||
const NUM_NODES: usize = 1;
|
||||
let num_archivers = 1;
|
||||
let config = ClusterConfig {
|
||||
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
|
||||
num_archivers,
|
||||
node_stakes: vec![3; NUM_NODES],
|
||||
cluster_lamports: 100,
|
||||
ticks_per_slot: 8,
|
||||
@@ -748,6 +595,5 @@ mod test {
|
||||
};
|
||||
let cluster = LocalCluster::new(&config);
|
||||
assert_eq!(cluster.validators.len(), NUM_NODES);
|
||||
assert_eq!(cluster.archivers.len(), num_archivers);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user