Populate test ledgers with a full slots to reduce test boilerplate
This commit is contained in:
parent
033a04129a
commit
55a76ed4b0
|
@ -1,5 +1,5 @@
|
|||
use assert_cmd::prelude::*;
|
||||
use solana::blocktree::create_tmp_sample_blocktree;
|
||||
use solana::blocktree::create_new_tmp_ledger;
|
||||
use solana_sdk::genesis_block::GenesisBlock;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use std::process::Command;
|
||||
|
@ -34,12 +34,10 @@ fn nominal() {
|
|||
let keypair = Arc::new(Keypair::new());
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(100, keypair.pubkey(), 50);
|
||||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
let (ledger_path, tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"test_ledger_tool_nominal",
|
||||
&genesis_block,
|
||||
ticks_per_slot - 2,
|
||||
);
|
||||
|
||||
let (ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("test_ledger_tool_nominal", &genesis_block).unwrap();
|
||||
let ticks = ticks_per_slot as usize;
|
||||
|
||||
// Basic validation
|
||||
let output = run_ledger_tool(&["-l", &ledger_path, "verify"]);
|
||||
|
@ -48,7 +46,7 @@ fn nominal() {
|
|||
// Print everything
|
||||
let output = run_ledger_tool(&["-l", &ledger_path, "print"]);
|
||||
assert!(output.status.success());
|
||||
assert_eq!(count_newlines(&output.stdout), tick_height as usize);
|
||||
assert_eq!(count_newlines(&output.stdout), ticks);
|
||||
|
||||
// Only print the first 5 items
|
||||
let output = run_ledger_tool(&["-l", &ledger_path, "-n", "5", "print"]);
|
||||
|
@ -58,7 +56,7 @@ fn nominal() {
|
|||
// Skip entries with no hashes
|
||||
let output = run_ledger_tool(&["-l", &ledger_path, "-h", "1", "print"]);
|
||||
assert!(output.status.success());
|
||||
assert_eq!(count_newlines(&output.stdout), tick_height as usize);
|
||||
assert_eq!(count_newlines(&output.stdout), ticks);
|
||||
|
||||
// Skip entries with fewer than 2 hashes (skip everything)
|
||||
let output = run_ledger_tool(&["-l", &ledger_path, "-h", "2", "print"]);
|
||||
|
|
|
@ -1237,23 +1237,20 @@ impl Iterator for EntryIterator {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns a tuple (entry_height, tick_height, last_id), corresponding to the
|
||||
// total number of entries, the number of ticks, and the last id generated in the
|
||||
// new ledger
|
||||
pub fn create_new_ledger(
|
||||
ledger_path: &str,
|
||||
genesis_block: &GenesisBlock,
|
||||
) -> Result<(u64, u64, Hash)> {
|
||||
// Creates a new ledger with slot 0 full of ticks (and only ticks).
|
||||
//
|
||||
// Returns the last_id that can be used to start slot 1 entries with.
|
||||
pub fn create_new_ledger(ledger_path: &str, genesis_block: &GenesisBlock) -> Result<Hash> {
|
||||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
Blocktree::destroy(ledger_path)?;
|
||||
genesis_block.write(&ledger_path)?;
|
||||
|
||||
// Add a single tick linked back to the genesis_block to bootstrap the ledger
|
||||
// Fill slot 0 with ticks that link back to the genesis_block to bootstrap the ledger.
|
||||
let blocktree = Blocktree::open_config(ledger_path, ticks_per_slot)?;
|
||||
let entries = crate::entry::create_ticks(1, genesis_block.last_id());
|
||||
let entries = crate::entry::create_ticks(genesis_block.ticks_per_slot, genesis_block.last_id());
|
||||
blocktree.write_entries(0, 0, 0, &entries)?;
|
||||
|
||||
Ok((1, 1, entries[0].id))
|
||||
Ok(entries.last().unwrap().id)
|
||||
}
|
||||
|
||||
pub fn genesis<'a, I>(ledger_path: &str, entries: I) -> Result<()>
|
||||
|
@ -1306,37 +1303,13 @@ pub fn get_tmp_ledger_path(name: &str) -> String {
|
|||
path
|
||||
}
|
||||
|
||||
pub fn create_tmp_sample_blocktree(
|
||||
name: &str,
|
||||
genesis_block: &GenesisBlock,
|
||||
num_extra_ticks: u64,
|
||||
) -> (String, u64, u64, Hash, Hash) {
|
||||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
|
||||
// Same as `create_new_ledger()` but use a temporary ledger name based on the provided `name`
|
||||
//
|
||||
// Note: like `create_new_ledger` the returned ledger will have slot 0 full of ticks (and only
|
||||
// ticks)
|
||||
pub fn create_new_tmp_ledger(name: &str, genesis_block: &GenesisBlock) -> Result<(String, Hash)> {
|
||||
let ledger_path = get_tmp_ledger_path(name);
|
||||
let (mut entry_height, mut tick_height, mut last_entry_id) =
|
||||
create_new_ledger(&ledger_path, &genesis_block).unwrap();
|
||||
|
||||
let mut last_id = genesis_block.last_id();
|
||||
if num_extra_ticks > 0 {
|
||||
let entries = crate::entry::create_ticks(num_extra_ticks, last_entry_id);
|
||||
|
||||
let blocktree = Blocktree::open_config(&ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, entry_height, &entries)
|
||||
.unwrap();
|
||||
tick_height += num_extra_ticks;
|
||||
entry_height += entries.len() as u64;
|
||||
last_id = entries.last().unwrap().id;
|
||||
last_entry_id = last_id;
|
||||
}
|
||||
(
|
||||
ledger_path,
|
||||
tick_height,
|
||||
entry_height,
|
||||
last_id,
|
||||
last_entry_id,
|
||||
)
|
||||
create_new_ledger(&ledger_path, genesis_block).and_then(|last_id| Ok((ledger_path, last_id)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
|
@ -149,7 +149,7 @@ pub fn process_blocktree(
|
|||
if slot == 0 {
|
||||
// The first entry in the ledger is a pseudo-tick used only to ensure the number of ticks
|
||||
// in slot 0 is the same as the number of ticks in all subsequent slots. It is not
|
||||
// registered as a tick and thus cannot be used as a last_id
|
||||
// processed by the bank, skip over it.
|
||||
if entries.is_empty() {
|
||||
warn!("entry0 not present");
|
||||
return Err(BankError::LedgerVerificationFailed);
|
||||
|
@ -164,7 +164,6 @@ pub fn process_blocktree(
|
|||
entries = entries.drain(1..).collect();
|
||||
}
|
||||
|
||||
// Feed the entries into the bank for this slot
|
||||
if !entries.is_empty() {
|
||||
if !entries.verify(&last_entry_id) {
|
||||
warn!("Ledger proof of history failed at entry: {}", entry_height);
|
||||
|
@ -228,7 +227,7 @@ pub fn process_blocktree(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::blocktree::create_tmp_sample_blocktree;
|
||||
use crate::blocktree::create_new_tmp_ledger;
|
||||
use crate::blocktree::tests::entries_to_blobs;
|
||||
use crate::entry::{create_ticks, next_entry, Entry};
|
||||
use solana_sdk::genesis_block::GenesisBlock;
|
||||
|
@ -258,32 +257,45 @@ mod tests {
|
|||
let (genesis_block, _mint_keypair) = GenesisBlock::new(10_000);
|
||||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
|
||||
// Create a new ledger with slot 0 full of ticks
|
||||
let (ledger_path, tick_height, _entry_height, _last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"blocktree_with_incomplete_slot",
|
||||
&genesis_block,
|
||||
ticks_per_slot - 2, // last tick missing in slot 0
|
||||
);
|
||||
debug!("ledger_path: {:?}", ledger_path);
|
||||
assert_eq!(tick_height, ticks_per_slot - 1);
|
||||
|
||||
/*
|
||||
Build a blocktree in the ledger with the following fork structure:
|
||||
|
||||
slot 0
|
||||
|
|
||||
slot 1
|
||||
|
|
||||
slot 2
|
||||
|
||||
where slot 0 is incomplete
|
||||
where slot 1 is incomplete (missing 1 tick at the end)
|
||||
*/
|
||||
|
||||
// Create a new ledger with slot 0 full of ticks
|
||||
let (ledger_path, mut last_id) =
|
||||
create_new_tmp_ledger("blocktree_with_two_forks", &genesis_block).unwrap();
|
||||
debug!("ledger_path: {:?}", ledger_path);
|
||||
|
||||
let blocktree = Blocktree::open_config(&ledger_path, ticks_per_slot)
|
||||
.expect("Expected to successfully open database ledger");
|
||||
|
||||
// slot 1, points at slot 0
|
||||
let _last_slot1_entry_id =
|
||||
fill_blocktree_slot_with_ticks(&blocktree, ticks_per_slot, 1, 0, last_entry_id);
|
||||
let expected_last_entry_id;
|
||||
|
||||
// Write slot 1
|
||||
// slot 1, points at slot 0. Missing one tick
|
||||
{
|
||||
let parent_slot = 0;
|
||||
let slot = 1;
|
||||
let mut entries = create_ticks(ticks_per_slot, last_id);
|
||||
last_id = entries.last().unwrap().id;
|
||||
|
||||
entries.pop();
|
||||
expected_last_entry_id = entries.last().unwrap().id;
|
||||
|
||||
let blobs = entries_to_blobs(&entries, slot, parent_slot);
|
||||
blocktree.insert_data_blobs(blobs.iter()).unwrap();
|
||||
}
|
||||
|
||||
// slot 2, points at slot 1
|
||||
fill_blocktree_slot_with_ticks(&blocktree, ticks_per_slot, 2, 1, last_id);
|
||||
|
||||
let (mut _bank_forks, bank_forks_info) =
|
||||
process_blocktree(&genesis_block, &blocktree).unwrap();
|
||||
|
@ -292,9 +304,9 @@ mod tests {
|
|||
assert_eq!(
|
||||
bank_forks_info[0],
|
||||
BankForksInfo {
|
||||
bank_id: 0, // never finished first slot
|
||||
entry_height: ticks_per_slot - 1,
|
||||
last_entry_id: last_entry_id,
|
||||
bank_id: 1, // never finished first slot
|
||||
entry_height: 2 * ticks_per_slot - 1,
|
||||
last_entry_id: expected_last_entry_id,
|
||||
next_blob_index: ticks_per_slot - 1,
|
||||
}
|
||||
);
|
||||
|
@ -308,14 +320,10 @@ mod tests {
|
|||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
|
||||
// Create a new ledger with slot 0 full of ticks
|
||||
let (ledger_path, tick_height, _entry_height, _last_id, mut last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"blocktree_with_two_forks",
|
||||
&genesis_block,
|
||||
ticks_per_slot - 1,
|
||||
);
|
||||
let (ledger_path, last_id) =
|
||||
create_new_tmp_ledger("blocktree_with_two_forks", &genesis_block).unwrap();
|
||||
debug!("ledger_path: {:?}", ledger_path);
|
||||
assert_eq!(tick_height, ticks_per_slot);
|
||||
let mut last_entry_id = last_id;
|
||||
|
||||
/*
|
||||
Build a blocktree in the ledger with the following fork structure:
|
||||
|
@ -439,11 +447,12 @@ mod tests {
|
|||
fn test_process_ledger_simple() {
|
||||
let leader_pubkey = Keypair::new().pubkey();
|
||||
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(100, leader_pubkey, 50);
|
||||
let (ledger_path, tick_height, mut entry_height, mut last_id, mut last_entry_id) =
|
||||
create_tmp_sample_blocktree("process_ledger_simple", &genesis_block, 0);
|
||||
let (ledger_path, last_id) =
|
||||
create_new_tmp_ledger("process_ledger_simple", &genesis_block).unwrap();
|
||||
debug!("ledger_path: {:?}", ledger_path);
|
||||
|
||||
let mut entries = vec![];
|
||||
let mut last_entry_id = last_id;
|
||||
for _ in 0..3 {
|
||||
// Transfer one token from the mint to a random account
|
||||
let keypair = Keypair::new();
|
||||
|
@ -461,37 +470,30 @@ mod tests {
|
|||
entries.push(entry);
|
||||
}
|
||||
|
||||
// Add a tick for good measure
|
||||
let tick = Entry::new(&last_entry_id, 1, vec![]);
|
||||
last_entry_id = tick.id;
|
||||
last_id = last_entry_id;
|
||||
entries.push(tick);
|
||||
// Fill up the rest of slot 1 with ticks
|
||||
entries.extend(create_ticks(genesis_block.ticks_per_slot, last_entry_id));
|
||||
|
||||
let blocktree =
|
||||
Blocktree::open(&ledger_path).expect("Expected to successfully open database ledger");
|
||||
|
||||
blocktree
|
||||
.write_entries(0, tick_height, entry_height, &entries)
|
||||
.unwrap();
|
||||
entry_height += entries.len() as u64;
|
||||
|
||||
blocktree.write_entries(1, 0, 0, &entries).unwrap();
|
||||
let entry_height = genesis_block.ticks_per_slot + entries.len() as u64;
|
||||
let (bank_forks, bank_forks_info) = process_blocktree(&genesis_block, &blocktree).unwrap();
|
||||
|
||||
assert_eq!(bank_forks_info.len(), 1);
|
||||
assert_eq!(
|
||||
bank_forks_info[0],
|
||||
BankForksInfo {
|
||||
bank_id: 0,
|
||||
bank_id: 1,
|
||||
entry_height,
|
||||
last_entry_id,
|
||||
next_blob_index: entry_height,
|
||||
last_entry_id: entries.last().unwrap().id,
|
||||
next_blob_index: entries.len() as u64,
|
||||
}
|
||||
);
|
||||
|
||||
let bank = bank_forks.working_bank();
|
||||
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 50 - 3);
|
||||
assert_eq!(bank.tick_height(), 1);
|
||||
assert_eq!(bank.last_id(), last_id);
|
||||
assert_eq!(bank.tick_height(), 2 * genesis_block.ticks_per_slot - 1);
|
||||
assert_eq!(bank.last_id(), entries.last().unwrap().id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
114
src/fullnode.rs
114
src/fullnode.rs
|
@ -445,28 +445,20 @@ impl Service for Fullnode {
|
|||
}
|
||||
}
|
||||
|
||||
// Create entries such the node identified by active_keypair
|
||||
// will be added to the active set for leader selection:
|
||||
// 1) Give the node a nonzero number of tokens,
|
||||
// 2) A vote from the validator
|
||||
// Create entries such the node identified by active_keypair will be added to the active set for
|
||||
// leader selection, and append `num_ending_ticks` empty tick entries.
|
||||
pub fn make_active_set_entries(
|
||||
active_keypair: &Arc<Keypair>,
|
||||
token_source: &Keypair,
|
||||
stake: u64,
|
||||
slot_height_to_vote_on: u64,
|
||||
last_entry_id: &Hash,
|
||||
last_tick_id: &Hash,
|
||||
last_id: &Hash,
|
||||
num_ending_ticks: u64,
|
||||
) -> (Vec<Entry>, VotingKeypair) {
|
||||
// 1) Assume the active_keypair node has no tokens staked
|
||||
let transfer_tx = SystemTransaction::new_account(
|
||||
&token_source,
|
||||
active_keypair.pubkey(),
|
||||
stake,
|
||||
*last_tick_id,
|
||||
0,
|
||||
);
|
||||
let mut last_entry_id = *last_entry_id;
|
||||
let transfer_tx =
|
||||
SystemTransaction::new_account(&token_source, active_keypair.pubkey(), stake, *last_id, 0);
|
||||
let mut last_entry_id = *last_id;
|
||||
let transfer_entry = next_entry_mut(&mut last_entry_id, 1, vec![transfer_tx]);
|
||||
|
||||
// 2) Create and register a vote account for active_keypair
|
||||
|
@ -474,25 +466,25 @@ pub fn make_active_set_entries(
|
|||
let vote_account_id = voting_keypair.pubkey();
|
||||
|
||||
let new_vote_account_tx =
|
||||
VoteTransaction::new_account(active_keypair, vote_account_id, *last_tick_id, 1, 1);
|
||||
VoteTransaction::new_account(active_keypair, vote_account_id, *last_id, 1, 1);
|
||||
let new_vote_account_entry = next_entry_mut(&mut last_entry_id, 1, vec![new_vote_account_tx]);
|
||||
|
||||
// 3) Create vote entry
|
||||
let vote_tx =
|
||||
VoteTransaction::new_vote(&voting_keypair, slot_height_to_vote_on, *last_tick_id, 0);
|
||||
let vote_tx = VoteTransaction::new_vote(&voting_keypair, slot_height_to_vote_on, *last_id, 0);
|
||||
let vote_entry = next_entry_mut(&mut last_entry_id, 1, vec![vote_tx]);
|
||||
|
||||
// 4) Create the ending empty ticks
|
||||
let mut txs = vec![transfer_entry, new_vote_account_entry, vote_entry];
|
||||
// 4) Create `num_ending_ticks` empty ticks
|
||||
let mut entries = vec![transfer_entry, new_vote_account_entry, vote_entry];
|
||||
let empty_ticks = create_ticks(num_ending_ticks, last_entry_id);
|
||||
txs.extend(empty_ticks);
|
||||
(txs, voting_keypair)
|
||||
entries.extend(empty_ticks);
|
||||
|
||||
(entries, voting_keypair)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::blocktree::{create_tmp_sample_blocktree, tmp_copy_blocktree};
|
||||
use crate::blocktree::{create_new_tmp_ledger, tmp_copy_blocktree};
|
||||
use crate::entry::make_consecutive_blobs;
|
||||
use crate::streamer::responder;
|
||||
use solana_sdk::hash::Hash;
|
||||
|
@ -509,8 +501,8 @@ mod tests {
|
|||
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
|
||||
let (genesis_block, _mint_keypair) =
|
||||
GenesisBlock::new_with_leader(10_000, leader_keypair.pubkey(), 1000);
|
||||
let (validator_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("validator_exit", &genesis_block, 0);
|
||||
let (validator_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("validator_exit", &genesis_block).unwrap();
|
||||
|
||||
let validator = Fullnode::new(
|
||||
validator_node,
|
||||
|
@ -536,17 +528,11 @@ mod tests {
|
|||
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
|
||||
let (genesis_block, _mint_keypair) =
|
||||
GenesisBlock::new_with_leader(10_000, leader_keypair.pubkey(), 1000);
|
||||
let (
|
||||
validator_ledger_path,
|
||||
_tick_height,
|
||||
_last_entry_height,
|
||||
_last_id,
|
||||
_last_entry_id,
|
||||
) = create_tmp_sample_blocktree(
|
||||
let (validator_ledger_path, _last_id) = create_new_tmp_ledger(
|
||||
&format!("validator_parallel_exit_{}", i),
|
||||
&genesis_block,
|
||||
0,
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
ledger_paths.push(validator_ledger_path.clone());
|
||||
Fullnode::new(
|
||||
validator_node,
|
||||
|
@ -594,13 +580,8 @@ mod tests {
|
|||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
genesis_block.slots_per_epoch = slots_per_epoch;
|
||||
|
||||
let (
|
||||
bootstrap_leader_ledger_path,
|
||||
_tick_height,
|
||||
_genesis_entry_height,
|
||||
_last_id,
|
||||
_last_entry_id,
|
||||
) = create_tmp_sample_blocktree("test_leader_to_leader_transition", &genesis_block, 1);
|
||||
let (bootstrap_leader_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("test_leader_to_leader_transition", &genesis_block).unwrap();
|
||||
|
||||
// Start the bootstrap leader
|
||||
let bootstrap_leader = Fullnode::new(
|
||||
|
@ -617,10 +598,6 @@ mod tests {
|
|||
|
||||
// Wait for the bootstrap leader to transition. Since there are no other nodes in the
|
||||
// cluster it will continue to be the leader
|
||||
assert_eq!(
|
||||
rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 1)
|
||||
|
@ -630,7 +607,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_wrong_role_transition() {
|
||||
fn test_ledger_role_transition() {
|
||||
solana_logger::setup();
|
||||
|
||||
let fullnode_config = FullnodeConfig::default();
|
||||
|
@ -642,14 +619,11 @@ mod tests {
|
|||
let validator_keypair = Arc::new(Keypair::new());
|
||||
let (bootstrap_leader_node, validator_node, bootstrap_leader_ledger_path, _, _) =
|
||||
setup_leader_validator(
|
||||
"test_wrong_role_transition",
|
||||
&bootstrap_leader_keypair,
|
||||
&validator_keypair,
|
||||
0,
|
||||
// Generate enough ticks for an epochs to flush the bootstrap_leader's vote at
|
||||
// tick_height = 0 from the leader scheduler's active window
|
||||
ticks_per_slot * slots_per_epoch,
|
||||
"test_wrong_role_transition",
|
||||
ticks_per_slot,
|
||||
0,
|
||||
);
|
||||
let bootstrap_leader_info = bootstrap_leader_node.info.clone();
|
||||
|
||||
|
@ -723,12 +697,11 @@ mod tests {
|
|||
let fullnode_config = FullnodeConfig::default();
|
||||
let (leader_node, validator_node, validator_ledger_path, ledger_initial_len, last_id) =
|
||||
setup_leader_validator(
|
||||
"test_validator_to_leader_transition",
|
||||
&leader_keypair,
|
||||
&validator_keypair,
|
||||
0,
|
||||
0,
|
||||
"test_validator_to_leader_transition",
|
||||
ticks_per_slot,
|
||||
0,
|
||||
);
|
||||
|
||||
let leader_id = leader_keypair.pubkey();
|
||||
|
@ -800,50 +773,39 @@ mod tests {
|
|||
}
|
||||
|
||||
fn setup_leader_validator(
|
||||
test_name: &str,
|
||||
leader_keypair: &Arc<Keypair>,
|
||||
validator_keypair: &Arc<Keypair>,
|
||||
num_genesis_ticks: u64,
|
||||
num_ending_ticks: u64,
|
||||
test_name: &str,
|
||||
ticks_per_slot: u64,
|
||||
num_ending_slots: u64,
|
||||
) -> (Node, Node, String, u64, Hash) {
|
||||
info!("validator: {}", validator_keypair.pubkey());
|
||||
info!("leader: {}", leader_keypair.pubkey());
|
||||
// Make a leader identity
|
||||
let leader_node = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
|
||||
// Create validator identity
|
||||
assert!(num_genesis_ticks <= ticks_per_slot);
|
||||
let leader_node = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
|
||||
|
||||
let (mut genesis_block, mint_keypair) =
|
||||
GenesisBlock::new_with_leader(10_000, leader_node.info.id, 500);
|
||||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
|
||||
let (ledger_path, tick_height, mut entry_height, last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree(test_name, &genesis_block, num_genesis_ticks);
|
||||
let (ledger_path, last_id) = create_new_tmp_ledger(test_name, &genesis_block).unwrap();
|
||||
|
||||
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
|
||||
|
||||
// Write two entries so that the validator is in the active set:
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
// Add entries so that the validator is in the active set, then finish up the slot with
|
||||
// ticks (and maybe add extra slots full of empty ticks)
|
||||
let (entries, _) = make_active_set_entries(
|
||||
validator_keypair,
|
||||
&mint_keypair,
|
||||
10,
|
||||
0,
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
num_ending_ticks,
|
||||
ticks_per_slot * (num_ending_slots + 1),
|
||||
);
|
||||
|
||||
let blocktree = Blocktree::open_config(&ledger_path, ticks_per_slot).unwrap();
|
||||
let active_set_entries_len = active_set_entries.len() as u64;
|
||||
let last_id = active_set_entries.last().unwrap().id;
|
||||
|
||||
blocktree
|
||||
.write_entries(0, tick_height, entry_height, active_set_entries)
|
||||
.unwrap();
|
||||
|
||||
entry_height += active_set_entries_len;
|
||||
let last_id = entries.last().unwrap().id;
|
||||
let entry_height = ticks_per_slot + entries.len() as u64;
|
||||
blocktree.write_entries(1, 0, 0, entries).unwrap();
|
||||
|
||||
(
|
||||
leader_node,
|
||||
|
|
|
@ -462,7 +462,7 @@ impl Service for ReplayStage {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::blocktree::{create_tmp_sample_blocktree, Blocktree};
|
||||
use crate::blocktree::create_new_tmp_ledger;
|
||||
use crate::cluster_info::{ClusterInfo, Node};
|
||||
use crate::entry::create_ticks;
|
||||
use crate::entry::{next_entry_mut, Entry};
|
||||
|
@ -473,134 +473,10 @@ mod test {
|
|||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Fix this test to not send all entries in slot 0
|
||||
pub fn test_replay_stage_leader_rotation_exit() {
|
||||
solana_logger::setup();
|
||||
|
||||
// Set up dummy node to host a ReplayStage
|
||||
let my_keypair = Keypair::new();
|
||||
let my_id = my_keypair.pubkey();
|
||||
let my_node = Node::new_localhost_with_pubkey(my_id);
|
||||
let cluster_info_me = ClusterInfo::new(my_node.info.clone());
|
||||
|
||||
// Create keypair for the old leader
|
||||
let old_leader_id = Keypair::new().pubkey();
|
||||
|
||||
// Set up the LeaderScheduler so that my_id becomes the leader for epoch 1
|
||||
let ticks_per_slot = 16;
|
||||
let (mut genesis_block, mint_keypair) =
|
||||
GenesisBlock::new_with_leader(10_000, old_leader_id, 500);
|
||||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
genesis_block.slots_per_epoch = 1;
|
||||
|
||||
// Create a ledger
|
||||
let (my_ledger_path, mut tick_height, entry_height, mut last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"test_replay_stage_leader_rotation_exit",
|
||||
&genesis_block,
|
||||
0,
|
||||
);
|
||||
|
||||
info!("my_id: {:?}", my_id);
|
||||
info!("old_leader_id: {:?}", old_leader_id);
|
||||
|
||||
let my_keypair = Arc::new(my_keypair);
|
||||
let num_ending_ticks = 0;
|
||||
let (active_set_entries, voting_keypair) = make_active_set_entries(
|
||||
&my_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1, // add a vote for tick_height = ticks_per_slot
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
num_ending_ticks,
|
||||
);
|
||||
last_id = active_set_entries.last().unwrap().id;
|
||||
|
||||
{
|
||||
let blocktree = Blocktree::open(&my_ledger_path).unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, entry_height, active_set_entries)
|
||||
.unwrap();
|
||||
tick_height += num_ending_ticks;
|
||||
}
|
||||
|
||||
{
|
||||
// Set up the bank
|
||||
let (bank_forks, bank_forks_info, blocktree, ledger_signal_receiver) =
|
||||
new_banks_from_blocktree(&my_ledger_path);
|
||||
|
||||
// Set up the replay stage
|
||||
let (rotation_sender, rotation_receiver) = channel();
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let blocktree = Arc::new(blocktree);
|
||||
let (replay_stage, ledger_writer_recv) = ReplayStage::new(
|
||||
my_id,
|
||||
Some(Arc::new(voting_keypair)),
|
||||
blocktree.clone(),
|
||||
&Arc::new(RwLock::new(bank_forks)),
|
||||
&bank_forks_info,
|
||||
Arc::new(RwLock::new(cluster_info_me)),
|
||||
exit.clone(),
|
||||
&rotation_sender,
|
||||
ledger_signal_receiver,
|
||||
&Arc::new(RpcSubscriptions::default()),
|
||||
);
|
||||
|
||||
let total_entries_to_send = 2 * ticks_per_slot as usize - 2;
|
||||
let mut entries_to_send = vec![];
|
||||
while entries_to_send.len() < total_entries_to_send {
|
||||
let entry = next_entry_mut(&mut last_id, 1, vec![]);
|
||||
entries_to_send.push(entry);
|
||||
}
|
||||
|
||||
// Write the entries to the ledger, replay_stage should get notified of changes
|
||||
let meta = blocktree.meta(0).unwrap().unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, meta.consumed, &entries_to_send)
|
||||
.unwrap();
|
||||
|
||||
info!("Wait for replay_stage to exit and check return value is correct");
|
||||
let rotation_info = rotation_receiver
|
||||
.recv()
|
||||
.expect("should have signaled leader rotation");
|
||||
assert_eq!(
|
||||
rotation_info.last_entry_id,
|
||||
bank_forks_info[0].last_entry_id
|
||||
);
|
||||
assert_eq!(rotation_info.slot, 2);
|
||||
assert_eq!(rotation_info.leader_id, my_keypair.pubkey());
|
||||
|
||||
info!("Check that the entries on the ledger writer channel are correct");
|
||||
let mut received_ticks = ledger_writer_recv
|
||||
.recv()
|
||||
.expect("Expected to receive an entry on the ledger writer receiver");
|
||||
|
||||
while let Ok(entries) = ledger_writer_recv.try_recv() {
|
||||
received_ticks.extend(entries);
|
||||
}
|
||||
let received_ticks_entries: Vec<Entry> = received_ticks
|
||||
.iter()
|
||||
.map(|entry_meta| entry_meta.entry.clone())
|
||||
.collect();
|
||||
assert_eq!(&received_ticks_entries[..], &entries_to_send[..]);
|
||||
|
||||
// Replay stage should continue running even after rotation has happened (tvu never goes down)
|
||||
assert_eq!(exit.load(Ordering::Relaxed), false);
|
||||
|
||||
info!("Close replay_stage");
|
||||
replay_stage
|
||||
.close()
|
||||
.expect("Expect successful ReplayStage exit");
|
||||
}
|
||||
let _ignored = remove_dir_all(&my_ledger_path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vote_error_replay_stage_correctness() {
|
||||
// Set up dummy node to host a ReplayStage
|
||||
|
@ -613,12 +489,9 @@ mod test {
|
|||
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(10_000, leader_id, 500);
|
||||
|
||||
let (my_ledger_path, tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"test_vote_error_replay_stage_correctness",
|
||||
&genesis_block,
|
||||
1,
|
||||
);
|
||||
let (my_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("test_vote_error_replay_stage_correctness", &genesis_block)
|
||||
.unwrap();
|
||||
|
||||
// Set up the cluster info
|
||||
let cluster_info_me = Arc::new(RwLock::new(ClusterInfo::new(my_node.info.clone())));
|
||||
|
@ -631,7 +504,6 @@ mod test {
|
|||
let (bank_forks, bank_forks_info, blocktree, l_receiver) =
|
||||
new_banks_from_blocktree(&my_ledger_path);
|
||||
let bank = bank_forks.working_bank();
|
||||
let entry_height = bank_forks_info[0].entry_height;
|
||||
let last_entry_id = bank_forks_info[0].last_entry_id;
|
||||
|
||||
let blocktree = Arc::new(blocktree);
|
||||
|
@ -654,9 +526,7 @@ mod test {
|
|||
|
||||
info!("Send ReplayStage an entry, should see it on the ledger writer receiver");
|
||||
let next_tick = create_ticks(1, last_entry_id);
|
||||
blocktree
|
||||
.write_entries(0, tick_height, entry_height, next_tick.clone())
|
||||
.unwrap();
|
||||
blocktree.write_entries(1, 0, 0, next_tick.clone()).unwrap();
|
||||
|
||||
let received_tick = ledger_writer_recv
|
||||
.recv()
|
||||
|
@ -671,137 +541,6 @@ mod test {
|
|||
let _ignored = remove_dir_all(&my_ledger_path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_vote_error_replay_stage_leader_rotation() {
|
||||
solana_logger::setup();
|
||||
|
||||
let ticks_per_slot = 10;
|
||||
let slots_per_epoch = 2;
|
||||
let active_window_tick_length = ticks_per_slot * slots_per_epoch;
|
||||
|
||||
// Set up dummy node to host a ReplayStage
|
||||
let my_keypair = Keypair::new();
|
||||
let my_id = my_keypair.pubkey();
|
||||
let my_node = Node::new_localhost_with_pubkey(my_id);
|
||||
|
||||
// Create keypair for the leader
|
||||
let leader_id = Keypair::new().pubkey();
|
||||
|
||||
let (mut genesis_block, mint_keypair) =
|
||||
GenesisBlock::new_with_leader(10_000, leader_id, 500);
|
||||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
|
||||
// Create the ledger
|
||||
let (my_ledger_path, tick_height, genesis_entry_height, last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"test_vote_error_replay_stage_leader_rotation",
|
||||
&genesis_block,
|
||||
1,
|
||||
);
|
||||
|
||||
let my_keypair = Arc::new(my_keypair);
|
||||
// Write two entries to the ledger so that the validator is in the active set:
|
||||
// 1) Give the validator a nonzero number of tokens 2) A vote from the validator.
|
||||
// This will cause leader rotation after the bootstrap height
|
||||
let (active_set_entries, voting_keypair) = make_active_set_entries(
|
||||
&my_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1,
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
0,
|
||||
);
|
||||
let mut last_id = active_set_entries.last().unwrap().id;
|
||||
{
|
||||
let blocktree = Blocktree::open_config(&my_ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, genesis_entry_height, &active_set_entries)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Set up the cluster info
|
||||
let cluster_info_me = Arc::new(RwLock::new(ClusterInfo::new(my_node.info.clone())));
|
||||
|
||||
// Set up the replay stage
|
||||
let (rotation_sender, rotation_receiver) = channel();
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
{
|
||||
let (bank_forks, bank_forks_info, blocktree, l_receiver) =
|
||||
new_banks_from_blocktree(&my_ledger_path);
|
||||
let bank = bank_forks.working_bank();
|
||||
let meta = blocktree
|
||||
.meta(0)
|
||||
.unwrap()
|
||||
.expect("First slot metadata must exist");
|
||||
|
||||
let voting_keypair = Arc::new(voting_keypair);
|
||||
let blocktree = Arc::new(blocktree);
|
||||
let (replay_stage, ledger_writer_recv) = ReplayStage::new(
|
||||
my_keypair.pubkey(),
|
||||
Some(voting_keypair.clone()),
|
||||
blocktree.clone(),
|
||||
&Arc::new(RwLock::new(bank_forks)),
|
||||
&bank_forks_info,
|
||||
cluster_info_me.clone(),
|
||||
exit.clone(),
|
||||
&rotation_sender,
|
||||
l_receiver,
|
||||
&Arc::new(RpcSubscriptions::default()),
|
||||
);
|
||||
|
||||
let keypair = voting_keypair.as_ref();
|
||||
let vote = VoteTransaction::new_vote(keypair, 0, bank.last_id(), 0);
|
||||
cluster_info_me.write().unwrap().push_vote(vote);
|
||||
|
||||
// Send enough ticks to trigger leader rotation
|
||||
let total_entries_to_send = (active_window_tick_length - tick_height) as usize;
|
||||
let num_hashes = 1;
|
||||
|
||||
let leader_rotation_index = (active_window_tick_length - tick_height - 1) as usize;
|
||||
let mut expected_last_id = Hash::default();
|
||||
for i in 0..total_entries_to_send {
|
||||
let entry = next_entry_mut(&mut last_id, num_hashes, vec![]);
|
||||
blocktree
|
||||
.write_entries(
|
||||
0,
|
||||
tick_height + i as u64,
|
||||
meta.consumed + i as u64,
|
||||
vec![entry.clone()],
|
||||
)
|
||||
.expect("Expected successful database write");
|
||||
// Check that the entries on the ledger writer channel are correct
|
||||
let received_entry = ledger_writer_recv
|
||||
.recv()
|
||||
.expect("Expected to recieve an entry on the ledger writer receiver");
|
||||
assert_eq!(received_entry[0].entry, entry);
|
||||
|
||||
if i == leader_rotation_index {
|
||||
expected_last_id = entry.id;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for replay_stage to exit and check return value is correct
|
||||
let rotation_info = rotation_receiver
|
||||
.recv()
|
||||
.expect("should have signaled leader rotation");
|
||||
assert_eq!(
|
||||
rotation_info.last_entry_id,
|
||||
bank_forks_info[0].last_entry_id
|
||||
);
|
||||
assert_eq!(rotation_info.slot, 1);
|
||||
assert_eq!(rotation_info.leader_id, my_keypair.pubkey());
|
||||
|
||||
assert_ne!(expected_last_id, Hash::default());
|
||||
//replay stage should continue running even after rotation has happened (tvu never goes down)
|
||||
replay_stage
|
||||
.close()
|
||||
.expect("Expect successful ReplayStage exit");
|
||||
}
|
||||
let _ignored = remove_dir_all(&my_ledger_path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replay_stage_poh_error_entry_receiver() {
|
||||
// Set up dummy node to host a ReplayStage
|
||||
|
|
|
@ -448,7 +448,7 @@ impl Service for StorageStage {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::blocktree::{create_tmp_sample_blocktree, Blocktree};
|
||||
use crate::blocktree::{create_new_tmp_ledger, Blocktree};
|
||||
use crate::cluster_info::{ClusterInfo, NodeInfo};
|
||||
use crate::entry::{make_tiny_test_entries, Entry, EntryMeta};
|
||||
use crate::service::Service;
|
||||
|
@ -509,14 +509,12 @@ mod tests {
|
|||
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new(1000);
|
||||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
let (ledger_path, tick_height, genesis_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("storage_stage_process_entries", &genesis_block, 1);
|
||||
let (ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("storage_stage_process_entries", &genesis_block).unwrap();
|
||||
|
||||
let entries = make_tiny_test_entries(64);
|
||||
let blocktree = Blocktree::open_config(&ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, genesis_entry_height, &entries)
|
||||
.unwrap();
|
||||
blocktree.write_entries(1, 0, 0, &entries).unwrap();
|
||||
|
||||
let cluster_info = test_cluster_info(keypair.pubkey());
|
||||
|
||||
|
@ -575,14 +573,12 @@ mod tests {
|
|||
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new(1000);
|
||||
let ticks_per_slot = genesis_block.ticks_per_slot;;
|
||||
let (ledger_path, tick_height, genesis_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("storage_stage_process_entries", &genesis_block, 1);
|
||||
let (ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("storage_stage_process_entries", &genesis_block).unwrap();
|
||||
|
||||
let entries = make_tiny_test_entries(128);
|
||||
let blocktree = Blocktree::open_config(&ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, genesis_entry_height, &entries)
|
||||
.unwrap();
|
||||
blocktree.write_entries(1, 0, 0, &entries).unwrap();
|
||||
|
||||
let cluster_info = test_cluster_info(keypair.pubkey());
|
||||
|
||||
|
|
|
@ -457,7 +457,7 @@ pub fn retry_get_balance(
|
|||
}
|
||||
|
||||
pub fn new_fullnode(ledger_name: &'static str) -> (Fullnode, NodeInfo, Keypair, String) {
|
||||
use crate::blocktree::create_tmp_sample_blocktree;
|
||||
use crate::blocktree::create_new_tmp_ledger;
|
||||
use crate::cluster_info::Node;
|
||||
use crate::fullnode::Fullnode;
|
||||
use crate::voting_keypair::VotingKeypair;
|
||||
|
@ -469,9 +469,7 @@ pub fn new_fullnode(ledger_name: &'static str) -> (Fullnode, NodeInfo, Keypair,
|
|||
let node_info = node.info.clone();
|
||||
|
||||
let (genesis_block, mint_keypair) = GenesisBlock::new_with_leader(10_000, node_info.id, 42);
|
||||
|
||||
let (ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree(ledger_name, &genesis_block, genesis_block.ticks_per_slot);
|
||||
let (ledger_path, _last_id) = create_new_tmp_ledger(ledger_name, &genesis_block).unwrap();
|
||||
|
||||
let vote_account_keypair = Arc::new(Keypair::new());
|
||||
let voting_keypair = VotingKeypair::new_local(&vote_account_keypair);
|
||||
|
@ -651,8 +649,10 @@ mod tests {
|
|||
|
||||
let mut client = mk_client(&leader_data);
|
||||
let last_id = client.get_last_id();
|
||||
info!("test_thin_client last_id: {:?}", last_id);
|
||||
|
||||
let starting_balance = client.poll_get_balance(&alice.pubkey()).unwrap();
|
||||
let starting_alice_balance = client.poll_get_balance(&alice.pubkey()).unwrap();
|
||||
info!("Alice has {} tokens", starting_alice_balance);
|
||||
|
||||
info!("Give Bob 500 tokens");
|
||||
let signature = client
|
||||
|
@ -660,20 +660,21 @@ mod tests {
|
|||
.unwrap();
|
||||
client.poll_for_signature(&signature).unwrap();
|
||||
|
||||
let balance = client.poll_get_balance(&bob_keypair.pubkey());
|
||||
assert_eq!(balance.unwrap(), 500);
|
||||
let bob_balance = client.poll_get_balance(&bob_keypair.pubkey());
|
||||
assert_eq!(bob_balance.unwrap(), 500);
|
||||
|
||||
info!("Take Bob's 500 tokens away");
|
||||
let signature = client
|
||||
.transfer(500, &bob_keypair, alice.pubkey(), &last_id)
|
||||
.unwrap();
|
||||
client.poll_for_signature(&signature).unwrap();
|
||||
let balance = client.poll_get_balance(&alice.pubkey()).unwrap();
|
||||
assert_eq!(balance, starting_balance);
|
||||
let alice_balance = client.poll_get_balance(&alice.pubkey()).unwrap();
|
||||
assert_eq!(alice_balance, starting_alice_balance);
|
||||
|
||||
info!("Should get an error when Bob's balance hits zero and is purged");
|
||||
let balance = client.poll_get_balance(&bob_keypair.pubkey());
|
||||
assert!(balance.is_err());
|
||||
let bob_balance = client.poll_get_balance(&bob_keypair.pubkey());
|
||||
info!("Bob's balance is {:?}", bob_balance);
|
||||
assert!(bob_balance.is_err(),);
|
||||
|
||||
server_exit();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
|
|
|
@ -3,7 +3,7 @@ extern crate solana;
|
|||
|
||||
use log::*;
|
||||
use solana::blob_fetch_stage::BlobFetchStage;
|
||||
use solana::blocktree::{create_tmp_sample_blocktree, tmp_copy_blocktree, Blocktree};
|
||||
use solana::blocktree::{create_new_tmp_ledger, tmp_copy_blocktree, Blocktree};
|
||||
use solana::client::mk_client;
|
||||
use solana::cluster_info::{Node, NodeInfo};
|
||||
use solana::entry::{reconstruct_entries_from_blobs, Entry};
|
||||
|
@ -52,8 +52,8 @@ fn test_multi_node_ledger_window() -> result::Result<()> {
|
|||
let ticks_per_slot = genesis_block.ticks_per_slot;
|
||||
info!("ticks_per_slot: {}", ticks_per_slot);
|
||||
|
||||
let (leader_ledger_path, tick_height, mut last_entry_height, _last_id, mut last_entry_id) =
|
||||
create_tmp_sample_blocktree("multi_node_ledger_window", &genesis_block, 0);
|
||||
let (leader_ledger_path, last_id) =
|
||||
create_new_tmp_ledger("multi_node_ledger_window", &genesis_block).unwrap();
|
||||
ledger_paths.push(leader_ledger_path.clone());
|
||||
|
||||
// make a copy at zero
|
||||
|
@ -62,25 +62,10 @@ fn test_multi_node_ledger_window() -> result::Result<()> {
|
|||
|
||||
// Write some into leader's ledger, this should populate the leader's window
|
||||
// and force it to respond to repair from the ledger window
|
||||
// TODO: write out more than slot 0
|
||||
{
|
||||
let blocktree = Blocktree::open_config(&leader_ledger_path, ticks_per_slot).unwrap();
|
||||
|
||||
let entries = solana::entry::create_ticks(
|
||||
genesis_block.ticks_per_slot - last_entry_height - 1,
|
||||
last_entry_id,
|
||||
);
|
||||
blocktree
|
||||
.write_entries(0, tick_height, last_entry_height, &entries)
|
||||
.unwrap();
|
||||
|
||||
last_entry_height += entries.len() as u64;
|
||||
last_entry_id = entries.last().unwrap().id;
|
||||
|
||||
info!(
|
||||
"Final last_entry_height: {}, last_entry_id: {:?}",
|
||||
last_entry_height, last_entry_id
|
||||
);
|
||||
let entries = solana::entry::create_ticks(genesis_block.ticks_per_slot, last_id);
|
||||
blocktree.write_entries(1, 0, 0, &entries).unwrap();
|
||||
}
|
||||
|
||||
let fullnode_config = FullnodeConfig::default();
|
||||
|
@ -168,9 +153,8 @@ fn test_multi_node_validator_catchup_from_zero() -> result::Result<()> {
|
|||
let mut ledger_paths = Vec::new();
|
||||
|
||||
let (genesis_block, alice) = GenesisBlock::new_with_leader(10_000, leader_data.id, 500);
|
||||
|
||||
let (genesis_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("multi_node_validator_catchup_from_zero", &genesis_block, 0);
|
||||
let (genesis_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("multi_node_validator_catchup_from_zero", &genesis_block).unwrap();
|
||||
ledger_paths.push(genesis_ledger_path.clone());
|
||||
|
||||
let zero_ledger_path = tmp_copy_blocktree!(&genesis_ledger_path);
|
||||
|
@ -346,8 +330,8 @@ fn test_multi_node_basic() {
|
|||
|
||||
let (genesis_block, alice) = GenesisBlock::new_with_leader(10_000, leader_data.id, 500);
|
||||
|
||||
let (genesis_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("multi_node_basic", &genesis_block, 0);
|
||||
let (genesis_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("multi_node_basic", &genesis_block).unwrap();
|
||||
ledger_paths.push(genesis_ledger_path.clone());
|
||||
|
||||
let leader_ledger_path = tmp_copy_blocktree!(&genesis_ledger_path);
|
||||
|
@ -448,9 +432,8 @@ fn test_boot_validator_from_file() {
|
|||
let mut ledger_paths = Vec::new();
|
||||
|
||||
let (genesis_block, alice) = GenesisBlock::new_with_leader(100_000, leader_pubkey, 1000);
|
||||
|
||||
let (genesis_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("boot_validator_from_file", &genesis_block, 0);
|
||||
let (genesis_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("boot_validator_from_file", &genesis_block).unwrap();
|
||||
ledger_paths.push(genesis_ledger_path.clone());
|
||||
|
||||
let leader_ledger_path = tmp_copy_blocktree!(&genesis_ledger_path);
|
||||
|
@ -500,8 +483,8 @@ fn test_boot_validator_from_file() {
|
|||
// TODO: it would be nice to determine the slot that the leader processed the transactions
|
||||
// in, and only wait for that slot here
|
||||
let expected_rotations = vec![
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 0),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 1),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 2),
|
||||
];
|
||||
|
||||
for expected_rotation in expected_rotations {
|
||||
|
@ -562,13 +545,11 @@ fn test_leader_restart_validator_start_from_old_ledger() -> result::Result<()> {
|
|||
leader_keypair.pubkey(),
|
||||
initial_leader_balance,
|
||||
);
|
||||
|
||||
let (ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"leader_restart_validator_start_from_old_ledger",
|
||||
&genesis_block,
|
||||
0,
|
||||
);
|
||||
let (ledger_path, _last_id) = create_new_tmp_ledger(
|
||||
"leader_restart_validator_start_from_old_ledger",
|
||||
&genesis_block,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
|
||||
|
@ -676,9 +657,8 @@ fn test_multi_node_dynamic_network() {
|
|||
let bob_pubkey = Keypair::new().pubkey();
|
||||
|
||||
let (genesis_block, alice) = GenesisBlock::new_with_leader(10_000_000, leader_pubkey, 500);
|
||||
|
||||
let (genesis_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("multi_node_dynamic_network", &genesis_block, 0);
|
||||
let (genesis_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("multi_node_dynamic_network", &genesis_block).unwrap();
|
||||
|
||||
let mut ledger_paths = Vec::new();
|
||||
ledger_paths.push(genesis_ledger_path.clone());
|
||||
|
@ -891,24 +871,23 @@ fn test_leader_to_validator_transition() {
|
|||
|
||||
// Initialize the leader ledger. Make a mint and a genesis entry
|
||||
// in the leader ledger
|
||||
let (leader_ledger_path, tick_height, genesis_entry_height, last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree("test_leader_to_validator_transition", &genesis_block, 0);
|
||||
let (leader_ledger_path, last_id) =
|
||||
create_new_tmp_ledger("test_leader_to_validator_transition", &genesis_block).unwrap();
|
||||
|
||||
// Write the votes entries to the ledger that will cause leader rotation
|
||||
// to validator_keypair at slot 2
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
&validator_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1,
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
0,
|
||||
);
|
||||
{
|
||||
let blocktree = Blocktree::open_config(&leader_ledger_path, ticks_per_slot).unwrap();
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
&validator_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1,
|
||||
&last_id,
|
||||
ticks_per_slot,
|
||||
);
|
||||
blocktree
|
||||
.write_entries(0, tick_height, genesis_entry_height, &active_set_entries)
|
||||
.write_entries(1, 0, 0, &active_set_entries)
|
||||
.unwrap();
|
||||
}
|
||||
info!("leader id: {}", leader_keypair.pubkey());
|
||||
|
@ -927,10 +906,7 @@ fn test_leader_to_validator_transition() {
|
|||
let (rotation_sender, rotation_receiver) = channel();
|
||||
let leader_exit = leader.run(Some(rotation_sender));
|
||||
|
||||
let expected_rotations = vec![
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 0),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 1),
|
||||
];
|
||||
let expected_rotations = vec![(FullnodeReturnType::LeaderToValidatorRotation, 2)];
|
||||
|
||||
for expected_rotation in expected_rotations {
|
||||
loop {
|
||||
|
@ -976,23 +952,22 @@ fn test_leader_validator_basic() {
|
|||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator ledgers
|
||||
let (leader_ledger_path, tick_height, genesis_entry_height, last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree("test_leader_validator_basic", &genesis_block, 0);
|
||||
let (leader_ledger_path, last_id) =
|
||||
create_new_tmp_ledger("test_leader_validator_basic", &genesis_block).unwrap();
|
||||
|
||||
// Add validator vote on tick height 1
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
&validator_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
0,
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
0,
|
||||
);
|
||||
{
|
||||
let blocktree = Blocktree::open_config(&leader_ledger_path, ticks_per_slot).unwrap();
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
&validator_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1,
|
||||
&last_id,
|
||||
ticks_per_slot,
|
||||
);
|
||||
blocktree
|
||||
.write_entries(0, tick_height, genesis_entry_height, &active_set_entries)
|
||||
.write_entries(1, 0, 0, &active_set_entries)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
@ -1030,28 +1005,18 @@ fn test_leader_validator_basic() {
|
|||
|
||||
converge(&leader_info, 2);
|
||||
|
||||
info!("Waiting for slot 0 -> slot 1: bootstrap leader and the validator rotate");
|
||||
assert_eq!(
|
||||
leader_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 0),
|
||||
);
|
||||
assert_eq!(
|
||||
leader_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 1)
|
||||
);
|
||||
assert_eq!(
|
||||
validator_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
validator_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::ValidatorToLeaderRotation, 1)
|
||||
);
|
||||
//
|
||||
// The ledger was populated with slot 0 and slot 1, so the first rotation should occur at slot 2
|
||||
//
|
||||
|
||||
info!("Waiting for slot 1 -> slot 2: validator remains the slot leader due to no votes");
|
||||
info!("Waiting for slot 1 -> slot 2: bootstrap leader and the validator rotate");
|
||||
assert_eq!(
|
||||
validator_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 2)
|
||||
(FullnodeReturnType::ValidatorToLeaderRotation, 2)
|
||||
);
|
||||
assert_eq!(
|
||||
leader_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 2),
|
||||
);
|
||||
|
||||
info!("Waiting for slot 2 -> slot 3: validator remains the slot leader due to no votes");
|
||||
|
@ -1059,6 +1024,20 @@ fn test_leader_validator_basic() {
|
|||
validator_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 3)
|
||||
);
|
||||
assert_eq!(
|
||||
leader_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 3)
|
||||
);
|
||||
|
||||
info!("Waiting for slot 3 -> slot 4: validator remains the slot leader due to no votes");
|
||||
assert_eq!(
|
||||
validator_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToLeaderRotation, 4)
|
||||
);
|
||||
assert_eq!(
|
||||
leader_rotation_receiver.recv().unwrap(),
|
||||
(FullnodeReturnType::LeaderToValidatorRotation, 4)
|
||||
);
|
||||
|
||||
info!("Shut down");
|
||||
validator_exit();
|
||||
|
@ -1106,13 +1085,8 @@ fn test_dropped_handoff_recovery() {
|
|||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator's ledgers
|
||||
let num_ending_ticks = 1;
|
||||
let (genesis_ledger_path, tick_height, genesis_entry_height, last_id, last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"test_dropped_handoff_recovery",
|
||||
&genesis_block,
|
||||
num_ending_ticks,
|
||||
);
|
||||
let (genesis_ledger_path, last_id) =
|
||||
create_new_tmp_ledger("test_dropped_handoff_recovery", &genesis_block).unwrap();
|
||||
|
||||
// Create the validator keypair that will be the next leader in line
|
||||
let next_leader_keypair = Arc::new(Keypair::new());
|
||||
|
@ -1125,21 +1099,18 @@ fn test_dropped_handoff_recovery() {
|
|||
|
||||
// Make the entries to give the next_leader validator some stake so that they will be in
|
||||
// leader election active set
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
&next_leader_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1,
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
0,
|
||||
);
|
||||
|
||||
// Write the entries
|
||||
{
|
||||
let blocktree = Blocktree::open_config(&genesis_ledger_path, ticks_per_slot).unwrap();
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
&next_leader_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
1,
|
||||
&last_id,
|
||||
ticks_per_slot,
|
||||
);
|
||||
blocktree
|
||||
.write_entries(0, tick_height, genesis_entry_height, &active_set_entries)
|
||||
.write_entries(1, 0, 0, &active_set_entries)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
@ -1264,45 +1235,36 @@ fn test_full_leader_validator_network() {
|
|||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator's ledgers
|
||||
let num_ending_ticks = 1;
|
||||
let (bootstrap_leader_ledger_path, tick_height, mut entry_height, last_id, mut last_entry_id) =
|
||||
create_tmp_sample_blocktree(
|
||||
"test_full_leader_validator_network",
|
||||
&genesis_block,
|
||||
num_ending_ticks,
|
||||
);
|
||||
let (bootstrap_leader_ledger_path, mut last_id) =
|
||||
create_new_tmp_ledger("test_full_leader_validator_network", &genesis_block).unwrap();
|
||||
|
||||
// Create a common ledger with entries in the beginnging that will add all the validators
|
||||
// to the active set for leader election.
|
||||
let mut ledger_paths = Vec::new();
|
||||
ledger_paths.push(bootstrap_leader_ledger_path.clone());
|
||||
|
||||
// Make entries to give each validator node some stake so that they will be in the
|
||||
// leader election active set
|
||||
let mut active_set_entries = vec![];
|
||||
for node_keypair in node_keypairs.iter() {
|
||||
// Make entries to give each validator node some stake so that they will be in the
|
||||
// leader election active set
|
||||
let (active_set_entries, _) = make_active_set_entries(
|
||||
let (node_active_set_entries, _) = make_active_set_entries(
|
||||
node_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
0,
|
||||
&last_entry_id,
|
||||
&last_id,
|
||||
0,
|
||||
ticks_per_slot,
|
||||
);
|
||||
last_id = node_active_set_entries.last().unwrap().id;
|
||||
active_set_entries.extend(node_active_set_entries);
|
||||
}
|
||||
|
||||
// Write the entries
|
||||
last_entry_id = active_set_entries
|
||||
.last()
|
||||
.expect("expected at least one genesis entry")
|
||||
.id;
|
||||
{
|
||||
let blocktree =
|
||||
Blocktree::open_config(&bootstrap_leader_ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(0, tick_height, entry_height, &active_set_entries)
|
||||
.unwrap();
|
||||
entry_height += active_set_entries.len() as u64;
|
||||
}
|
||||
{
|
||||
let blocktree =
|
||||
Blocktree::open_config(&bootstrap_leader_ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(1, 0, 0, &active_set_entries)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let mut nodes = vec![];
|
||||
|
@ -1462,16 +1424,9 @@ fn test_broadcast_last_tick() {
|
|||
genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
|
||||
// Create leader ledger
|
||||
let (
|
||||
bootstrap_leader_ledger_path,
|
||||
_tick_height,
|
||||
genesis_entry_height,
|
||||
_last_id,
|
||||
_last_entry_id,
|
||||
) = create_tmp_sample_blocktree("test_broadcast_last_tick", &genesis_block, 0);
|
||||
let (bootstrap_leader_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger("test_broadcast_last_tick", &genesis_block).unwrap();
|
||||
|
||||
let genesis_ledger_len = genesis_entry_height;
|
||||
debug!("genesis_ledger_len: {}", genesis_ledger_len);
|
||||
let blob_receiver_exit = Arc::new(AtomicBool::new(false));
|
||||
|
||||
// Create the listeners
|
||||
|
@ -1662,9 +1617,8 @@ fn test_fullnode_rotate(
|
|||
genesis_block.slots_per_epoch = slots_per_epoch;
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator ledgers
|
||||
let (leader_ledger_path, mut tick_height, mut last_entry_height, last_id, mut last_entry_id) =
|
||||
create_tmp_sample_blocktree("test_fullnode_rotate", &genesis_block, 0);
|
||||
assert_eq!(tick_height, 1);
|
||||
let (leader_ledger_path, mut last_id) =
|
||||
create_new_tmp_ledger("test_fullnode_rotate", &genesis_block).unwrap();
|
||||
|
||||
let mut ledger_paths = Vec::new();
|
||||
ledger_paths.push(leader_ledger_path.clone());
|
||||
|
@ -1676,6 +1630,19 @@ fn test_fullnode_rotate(
|
|||
let validator_keypair = Arc::new(Keypair::new());
|
||||
let validator = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
|
||||
|
||||
let mut leader_slot_height_of_next_rotation = 1;
|
||||
|
||||
if fullnode_config.leader_scheduler_config.ticks_per_slot == 1 {
|
||||
// Add another tick to the ledger if the cluster has been configured for 1 ticks_per_slot.
|
||||
// The "pseudo-tick" entry0 currently added by bank::process_ledger cannot be rotated on
|
||||
// since it has no last id (so at 1 ticks_per_slot rotation must start at a tick_height of
|
||||
// 2)
|
||||
let tick = solana::entry::create_ticks(1, last_id);
|
||||
last_id = tick[0].id;
|
||||
entries.extend(tick);
|
||||
leader_slot_height_of_next_rotation += 1;
|
||||
}
|
||||
|
||||
// Setup the cluster with a single node
|
||||
if include_validator {
|
||||
// Add validator vote on tick height 1
|
||||
|
@ -1683,40 +1650,22 @@ fn test_fullnode_rotate(
|
|||
&validator_keypair,
|
||||
&mint_keypair,
|
||||
100,
|
||||
0,
|
||||
&last_entry_id,
|
||||
1,
|
||||
&last_id,
|
||||
0,
|
||||
ticks_per_slot,
|
||||
);
|
||||
last_id = active_set_entries.last().unwrap().id;
|
||||
entries.extend(active_set_entries);
|
||||
last_entry_id = entries.last().unwrap().id;
|
||||
}
|
||||
|
||||
let mut start_slot = 0;
|
||||
let mut leader_tick_height_of_next_rotation = 2;
|
||||
if ticks_per_slot == 1 {
|
||||
// Add another tick to the ledger if the cluster has been configured for 1 tick_per_slot.
|
||||
// The "pseudo-tick" entry0 currently added by bank::process_ledger cannot be rotated on
|
||||
// since it has no last id (so at 1 ticks_per_slot rotation must start at a tick_height of
|
||||
// 2)
|
||||
let tick = solana::entry::create_ticks(1, last_entry_id);
|
||||
entries.extend(tick);
|
||||
last_entry_id = entries.last().unwrap().id;
|
||||
|
||||
start_slot = 1;
|
||||
tick_height = 0;
|
||||
last_entry_height = 0;
|
||||
leader_slot_height_of_next_rotation += 1;
|
||||
}
|
||||
|
||||
// Write additional ledger entries
|
||||
{
|
||||
trace!("last_entry_id: {:?}", last_entry_id);
|
||||
trace!("last_id: {:?}", last_id);
|
||||
trace!("entries: {:?}", entries);
|
||||
|
||||
let blocktree = Blocktree::open_config(&leader_ledger_path, ticks_per_slot).unwrap();
|
||||
blocktree
|
||||
.write_entries(start_slot, tick_height, last_entry_height, &entries)
|
||||
.unwrap();
|
||||
blocktree.write_entries(1, 0, 0, &entries).unwrap();
|
||||
}
|
||||
|
||||
// Start up the node(s)
|
||||
|
@ -1762,12 +1711,12 @@ fn test_fullnode_rotate(
|
|||
let mut client_last_id = solana_sdk::hash::Hash::default();
|
||||
|
||||
let mut validator_should_be_leader = !leader_should_be_leader;
|
||||
let mut validator_tick_height_of_next_rotation = leader_tick_height_of_next_rotation;
|
||||
let mut validator_slot_height_of_next_rotation = leader_slot_height_of_next_rotation;
|
||||
|
||||
let mut log_spam = 0;
|
||||
let max_tick_height = 8;
|
||||
while leader_tick_height_of_next_rotation < max_tick_height
|
||||
&& validator_tick_height_of_next_rotation < max_tick_height
|
||||
let max_slot_height = 5;
|
||||
while leader_slot_height_of_next_rotation < max_slot_height
|
||||
&& validator_slot_height_of_next_rotation < max_slot_height
|
||||
{
|
||||
// Check for leader rotation
|
||||
{
|
||||
|
@ -1779,7 +1728,7 @@ fn test_fullnode_rotate(
|
|||
}
|
||||
info!("leader rotation event {:?} at slot={}", rotation_type, slot);
|
||||
info!("leader should be leader? {}", leader_should_be_leader);
|
||||
assert_eq!(slot, leader_tick_height_of_next_rotation / ticks_per_slot);
|
||||
assert_eq!(slot, leader_slot_height_of_next_rotation);
|
||||
if include_validator {
|
||||
assert_eq!(
|
||||
rotation_type,
|
||||
|
@ -1793,7 +1742,7 @@ fn test_fullnode_rotate(
|
|||
} else {
|
||||
assert_eq!(rotation_type, FullnodeReturnType::LeaderToLeaderRotation);
|
||||
}
|
||||
leader_tick_height_of_next_rotation += ticks_per_slot;
|
||||
leader_slot_height_of_next_rotation += 1;
|
||||
}
|
||||
Err(TryRecvError::Empty) => {}
|
||||
err => panic!(err),
|
||||
|
@ -1810,13 +1759,10 @@ fn test_fullnode_rotate(
|
|||
}
|
||||
info!(
|
||||
"validator rotation event {:?} at slot={} {}",
|
||||
rotation_type, slot, validator_tick_height_of_next_rotation
|
||||
rotation_type, slot, validator_slot_height_of_next_rotation
|
||||
);
|
||||
info!("validator should be leader? {}", validator_should_be_leader);
|
||||
assert_eq!(
|
||||
slot,
|
||||
validator_tick_height_of_next_rotation / ticks_per_slot
|
||||
);
|
||||
assert_eq!(slot, validator_slot_height_of_next_rotation);
|
||||
assert_eq!(
|
||||
rotation_type,
|
||||
if validator_should_be_leader {
|
||||
|
@ -1825,7 +1771,7 @@ fn test_fullnode_rotate(
|
|||
FullnodeReturnType::ValidatorToLeaderRotation
|
||||
}
|
||||
);
|
||||
validator_tick_height_of_next_rotation += ticks_per_slot;
|
||||
validator_slot_height_of_next_rotation += 1;
|
||||
validator_should_be_leader = !validator_should_be_leader;
|
||||
}
|
||||
Err(TryRecvError::Empty) => {}
|
||||
|
@ -1866,16 +1812,15 @@ fn test_fullnode_rotate(
|
|||
});
|
||||
} else {
|
||||
log_spam += 1;
|
||||
if log_spam % 10 == 0 {
|
||||
if log_spam % 25 == 0 {
|
||||
if include_validator {
|
||||
trace!("waiting for leader and validator to reach max tick height...");
|
||||
trace!("waiting for leader and validator to reach max slot height...");
|
||||
} else {
|
||||
trace!("waiting for leader to reach max tick height...");
|
||||
trace!("waiting for leader to reach max slot height...");
|
||||
}
|
||||
}
|
||||
}
|
||||
tick_step_receiver.recv().expect("tick step");
|
||||
info!("tick step received");
|
||||
}
|
||||
|
||||
if transact {
|
||||
|
@ -1896,12 +1841,12 @@ fn test_fullnode_rotate(
|
|||
}
|
||||
|
||||
trace!(
|
||||
"final validator_tick_height_of_next_rotation: {}",
|
||||
validator_tick_height_of_next_rotation
|
||||
"final validator_slot_height_of_next_rotation: {}",
|
||||
validator_slot_height_of_next_rotation
|
||||
);
|
||||
trace!(
|
||||
"final leader_tick_height_of_next_rotation: {}",
|
||||
leader_tick_height_of_next_rotation
|
||||
"final leader_slot_height_of_next_rotation: {}",
|
||||
leader_slot_height_of_next_rotation
|
||||
);
|
||||
trace!("final leader_should_be_leader: {}", leader_should_be_leader);
|
||||
trace!(
|
||||
|
|
|
@ -10,7 +10,7 @@ extern crate solana;
|
|||
|
||||
use bincode::deserialize;
|
||||
use solana::blocktree::{
|
||||
create_tmp_sample_blocktree, get_tmp_ledger_path, tmp_copy_blocktree, Blocktree,
|
||||
create_new_tmp_ledger, get_tmp_ledger_path, tmp_copy_blocktree, Blocktree,
|
||||
};
|
||||
use solana::client::mk_client;
|
||||
use solana::cluster_info::{ClusterInfo, Node, NodeInfo};
|
||||
|
@ -47,8 +47,8 @@ fn test_replicator_startup_basic() {
|
|||
let (genesis_block, mint_keypair) =
|
||||
GenesisBlock::new_with_leader(1_000_000_000, leader_info.id, 42);
|
||||
|
||||
let (leader_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree(leader_ledger_path, &genesis_block, 0);
|
||||
let (leader_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger(leader_ledger_path, &genesis_block).unwrap();
|
||||
|
||||
let validator_ledger_path = tmp_copy_blocktree!(&leader_ledger_path);
|
||||
|
||||
|
@ -273,24 +273,22 @@ fn test_replicator_startup_leader_hang() {
|
|||
|
||||
#[test]
|
||||
fn test_replicator_startup_ledger_hang() {
|
||||
use std::net::UdpSocket;
|
||||
|
||||
solana_logger::setup();
|
||||
info!("starting replicator test");
|
||||
let leader_keypair = Arc::new(Keypair::new());
|
||||
|
||||
let (genesis_block, _mint_keypair) =
|
||||
GenesisBlock::new_with_leader(100, leader_keypair.pubkey(), 42);
|
||||
let (replicator_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree("replicator_test_replicator_ledger", &genesis_block, 0);
|
||||
let (replicator_test_replicator_ledger, _last_id) =
|
||||
create_new_tmp_ledger("replicator_test_replicator_ledger", &genesis_block).unwrap();
|
||||
|
||||
info!("starting leader node");
|
||||
let leader_node = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let leader_info = leader_node.info.clone();
|
||||
|
||||
let leader_ledger_path = "replicator_test_leader_ledger";
|
||||
let (leader_ledger_path, _tick_height, _last_entry_height, _last_id, _last_entry_id) =
|
||||
create_tmp_sample_blocktree(leader_ledger_path, &genesis_block, 0);
|
||||
let (leader_ledger_path, _last_id) =
|
||||
create_new_tmp_ledger(leader_ledger_path, &genesis_block).unwrap();
|
||||
|
||||
let validator_ledger_path = tmp_copy_blocktree!(&leader_ledger_path);
|
||||
|
||||
|
@ -325,7 +323,7 @@ fn test_replicator_startup_ledger_hang() {
|
|||
let mut replicator_node = Node::new_localhost_with_pubkey(bad_keys.pubkey());
|
||||
|
||||
// Pass bad TVU sockets to prevent successful ledger download
|
||||
replicator_node.sockets.tvu = vec![UdpSocket::bind("0.0.0.0:0").unwrap()];
|
||||
replicator_node.sockets.tvu = vec![std::net::UdpSocket::bind("0.0.0.0:0").unwrap()];
|
||||
|
||||
let leader_info = NodeInfo::new_entry_point(&leader_info.gossip);
|
||||
|
||||
|
|
Loading…
Reference in New Issue