Switch leader scheduler to use PoH ticks instead of Entry height (#1519)
* Add PoH height to process_ledger() * Moved broadcast_stage Leader Scheduling logic to use Poh height instead of entry_height * Moved LeaderScheduler logic to PoH in ReplicateStage * Fix Leader scheduling tests to use PoH instead of entry height * Change is_leader detection in repair() to use PoH instead of entry height * Add tests to LeaderScheduler for new functionality * fix Entry::new and genesis block PoH counts * Moved LeaderScheduler to PoH ticks * Cleanup to resolve PR comments
This commit is contained in:
@ -774,10 +774,8 @@ fn test_leader_to_validator_transition() {
|
||||
logger::setup();
|
||||
let leader_rotation_interval = 20;
|
||||
|
||||
// Make a dummy validator id to be the next leader and
|
||||
// sink for this test's mock transactions
|
||||
// Make a dummy validator id to be the next leader
|
||||
let validator_keypair = Keypair::new();
|
||||
let validator_id = validator_keypair.pubkey();
|
||||
|
||||
// Create the leader node information
|
||||
let leader_keypair = Keypair::new();
|
||||
@ -786,8 +784,12 @@ fn test_leader_to_validator_transition() {
|
||||
|
||||
// Initialize the leader ledger. Make a mint and a genesis entry
|
||||
// in the leader ledger
|
||||
let (mint, leader_ledger_path, genesis_entries) =
|
||||
create_tmp_sample_ledger("test_leader_to_validator_transition", 10_000);
|
||||
let num_ending_ticks = 1;
|
||||
let (mint, leader_ledger_path, genesis_entries) = create_tmp_sample_ledger(
|
||||
"test_leader_to_validator_transition",
|
||||
10_000,
|
||||
num_ending_ticks,
|
||||
);
|
||||
|
||||
let last_id = genesis_entries
|
||||
.last()
|
||||
@ -798,10 +800,8 @@ fn test_leader_to_validator_transition() {
|
||||
// after the bootstrap height
|
||||
let mut ledger_writer = LedgerWriter::open(&leader_ledger_path, false).unwrap();
|
||||
let bootstrap_entries =
|
||||
make_active_set_entries(&validator_keypair, &mint.keypair(), &last_id, &last_id);
|
||||
let bootstrap_entries_len = bootstrap_entries.len();
|
||||
make_active_set_entries(&validator_keypair, &mint.keypair(), &last_id, &last_id, 0);
|
||||
ledger_writer.write_entries(bootstrap_entries).unwrap();
|
||||
let ledger_initial_len = (genesis_entries.len() + bootstrap_entries_len) as u64;
|
||||
|
||||
// Start the leader node
|
||||
let bootstrap_height = leader_rotation_interval;
|
||||
@ -842,39 +842,25 @@ fn test_leader_to_validator_transition() {
|
||||
|
||||
assert!(converged);
|
||||
|
||||
let extra_transactions = std::cmp::max(bootstrap_height / 3, 1);
|
||||
// Account that will be the sink for all the test's transactions
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
|
||||
// Push leader "extra_transactions" past bootstrap_height,
|
||||
// make sure the leader stops.
|
||||
assert!(ledger_initial_len < bootstrap_height);
|
||||
for i in ledger_initial_len..(bootstrap_height + extra_transactions) {
|
||||
if i < bootstrap_height {
|
||||
// Poll to see that the bank state is updated after every transaction
|
||||
// to ensure that each transaction is packaged as a single entry,
|
||||
// so that we can be sure leader rotation is triggered
|
||||
let expected_balance = std::cmp::min(
|
||||
bootstrap_height - ledger_initial_len,
|
||||
i - ledger_initial_len + 1,
|
||||
);
|
||||
let result = send_tx_and_retry_get_balance(
|
||||
&leader_info,
|
||||
&mint,
|
||||
&validator_id,
|
||||
1,
|
||||
Some(expected_balance as i64),
|
||||
);
|
||||
// Push transactions until we detect an exit
|
||||
let mut i = 1;
|
||||
loop {
|
||||
// Poll to see that the bank state is updated after every transaction
|
||||
// to ensure that each transaction is packaged as a single entry,
|
||||
// so that we can be sure leader rotation is triggered
|
||||
let result =
|
||||
send_tx_and_retry_get_balance(&leader_info, &mint, &bob_pubkey, 1, Some(i as i64));
|
||||
|
||||
// If the transaction wasn't reflected in the node, then we assume
|
||||
// the node has transitioned already
|
||||
if result != Some(expected_balance as i64) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// After bootstrap entries, we don't care about the
|
||||
// number of entries generated by these transactions. These are just
|
||||
// here for testing to make sure the leader stopped at the correct point.
|
||||
send_tx_and_retry_get_balance(&leader_info, &mint, &validator_id, 1, None);
|
||||
// If the transaction wasn't reflected in the node, then we assume
|
||||
// the node has transitioned already
|
||||
if result != Some(i as i64) {
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Wait for leader to shut down tpu and restart tvu
|
||||
@ -883,25 +869,22 @@ fn test_leader_to_validator_transition() {
|
||||
_ => panic!("Expected reason for exit to be leader rotation"),
|
||||
}
|
||||
|
||||
// Query now validator to make sure that he has the proper balances in his bank
|
||||
// after the transitions, even though we submitted "extra_transactions"
|
||||
// transactions earlier
|
||||
// Query newly transitioned validator to make sure that he has the proper balances in
|
||||
// the after the transitions
|
||||
let mut leader_client = mk_client(&leader_info);
|
||||
|
||||
let maximum_bal = bootstrap_height - ledger_initial_len;
|
||||
let bal = leader_client
|
||||
.poll_get_balance(&validator_id)
|
||||
.expect("Expected success when polling newly transitioned validator for balance")
|
||||
as u64;
|
||||
|
||||
assert!(bal <= maximum_bal);
|
||||
// Leader could have executed transactions in bank but not recorded them, so
|
||||
// we only have an upper bound on the balance
|
||||
if let Ok(bal) = leader_client.poll_get_balance(&bob_pubkey) {
|
||||
assert!(bal <= i - 1);
|
||||
}
|
||||
|
||||
// Check the ledger to make sure it's the right height, we should've
|
||||
// transitioned after the bootstrap_height entry
|
||||
let (_, entry_height, _) =
|
||||
// transitioned after tick_height == bootstrap_height
|
||||
let (_, tick_height, _, _) =
|
||||
Fullnode::new_bank_from_ledger(&leader_ledger_path, &mut LeaderScheduler::default());
|
||||
|
||||
assert_eq!(entry_height, bootstrap_height);
|
||||
assert_eq!(tick_height, bootstrap_height);
|
||||
|
||||
// Shut down
|
||||
ncp.close().unwrap();
|
||||
@ -927,8 +910,9 @@ fn test_leader_validator_basic() {
|
||||
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator ledgers
|
||||
let num_ending_ticks = 1;
|
||||
let (mint, leader_ledger_path, genesis_entries) =
|
||||
create_tmp_sample_ledger("test_leader_to_validator_transition", 10_000);
|
||||
create_tmp_sample_ledger("test_leader_validator_basic", 10_000, num_ending_ticks);
|
||||
|
||||
let validator_ledger_path = tmp_copy_ledger(&leader_ledger_path, "test_leader_validator_basic");
|
||||
|
||||
@ -945,10 +929,9 @@ fn test_leader_validator_basic() {
|
||||
// Write the bootstrap entries to the ledger that will cause leader rotation
|
||||
// after the bootstrap height
|
||||
let mut ledger_writer = LedgerWriter::open(&leader_ledger_path, false).unwrap();
|
||||
let bootstrap_entries =
|
||||
make_active_set_entries(&validator_keypair, &mint.keypair(), &last_id, &last_id);
|
||||
let ledger_initial_len = (genesis_entries.len() + bootstrap_entries.len()) as u64;
|
||||
ledger_writer.write_entries(bootstrap_entries).unwrap();
|
||||
let active_set_entries =
|
||||
make_active_set_entries(&validator_keypair, &mint.keypair(), &last_id, &last_id, 0);
|
||||
ledger_writer.write_entries(active_set_entries).unwrap();
|
||||
|
||||
// Create the leader scheduler config
|
||||
let num_bootstrap_slots = 2;
|
||||
@ -985,22 +968,21 @@ fn test_leader_validator_basic() {
|
||||
let servers = converge(&leader_info, 2);
|
||||
assert_eq!(servers.len(), 2);
|
||||
|
||||
// Send transactions to the leader
|
||||
let extra_transactions = std::cmp::max(leader_rotation_interval / 3, 1);
|
||||
|
||||
// Push "extra_transactions" past leader_rotation_interval entry height,
|
||||
// make sure the validator stops.
|
||||
for i in ledger_initial_len..(bootstrap_height + extra_transactions) {
|
||||
let expected_balance = std::cmp::min(
|
||||
bootstrap_height - ledger_initial_len,
|
||||
i - ledger_initial_len + 1,
|
||||
);
|
||||
// Push transactions until we detect the nodes exit
|
||||
let mut i = 1;
|
||||
loop {
|
||||
// Poll to see that the bank state is updated after every transaction
|
||||
// to ensure that each transaction is packaged as a single entry,
|
||||
// so that we can be sure leader rotation is triggered
|
||||
let result = send_tx_and_retry_get_balance(&leader_info, &mint, &bob_pubkey, 1, None);
|
||||
|
||||
// If the transaction wasn't reflected in the node, then we assume
|
||||
// the node has transitioned already
|
||||
if result != Some(expected_balance as i64) {
|
||||
if result != Some(i as i64) {
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Wait for validator to shut down tvu and restart tpu
|
||||
@ -1015,6 +997,16 @@ fn test_leader_validator_basic() {
|
||||
_ => panic!("Expected reason for exit to be leader rotation"),
|
||||
}
|
||||
|
||||
// Query newly transitioned validator to make sure that he has the proper balances
|
||||
// in the bank after the transitions
|
||||
let mut leader_client = mk_client(&leader_info);
|
||||
|
||||
// Leader could have executed transactions in bank but not recorded them, so
|
||||
// we only have an upper bound on the balance
|
||||
if let Ok(bal) = leader_client.poll_get_balance(&bob_pubkey) {
|
||||
assert!(bal <= i - 1);
|
||||
}
|
||||
|
||||
// Shut down
|
||||
validator.close().unwrap();
|
||||
leader.close().unwrap();
|
||||
@ -1082,8 +1074,9 @@ fn test_dropped_handoff_recovery() {
|
||||
let bootstrap_leader_info = bootstrap_leader_node.info.clone();
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator's ledgers
|
||||
let num_ending_ticks = 1;
|
||||
let (mint, bootstrap_leader_ledger_path, genesis_entries) =
|
||||
create_tmp_sample_ledger("test_dropped_handoff_recovery", 10_000);
|
||||
create_tmp_sample_ledger("test_dropped_handoff_recovery", 10_000, num_ending_ticks);
|
||||
|
||||
let last_id = genesis_entries
|
||||
.last()
|
||||
@ -1101,15 +1094,12 @@ fn test_dropped_handoff_recovery() {
|
||||
|
||||
// Make the entries to give the next_leader validator some stake so that he will be in
|
||||
// leader election active set
|
||||
let first_entries =
|
||||
make_active_set_entries(&next_leader_keypair, &mint.keypair(), &last_id, &last_id);
|
||||
let first_entries_len = first_entries.len();
|
||||
let active_set_entries =
|
||||
make_active_set_entries(&next_leader_keypair, &mint.keypair(), &last_id, &last_id, 0);
|
||||
|
||||
// Write the entries
|
||||
let mut ledger_writer = LedgerWriter::open(&bootstrap_leader_ledger_path, false).unwrap();
|
||||
ledger_writer.write_entries(first_entries).unwrap();
|
||||
|
||||
let ledger_initial_len = (genesis_entries.len() + first_entries_len) as u64;
|
||||
ledger_writer.write_entries(active_set_entries).unwrap();
|
||||
|
||||
let next_leader_ledger_path = tmp_copy_ledger(
|
||||
&bootstrap_leader_ledger_path,
|
||||
@ -1119,10 +1109,13 @@ fn test_dropped_handoff_recovery() {
|
||||
ledger_paths.push(next_leader_ledger_path.clone());
|
||||
|
||||
// Create the common leader scheduling configuration
|
||||
let initial_tick_height = genesis_entries
|
||||
.iter()
|
||||
.fold(0, |tick_count, entry| tick_count + entry.is_tick() as u64);
|
||||
let num_slots_per_epoch = (N + 1) as u64;
|
||||
let leader_rotation_interval = 5;
|
||||
let seed_rotation_interval = num_slots_per_epoch * leader_rotation_interval;
|
||||
let bootstrap_height = ledger_initial_len + 1;
|
||||
let bootstrap_height = initial_tick_height + 1;
|
||||
let leader_scheduler_config = LeaderSchedulerConfig::new(
|
||||
bootstrap_leader_info.id,
|
||||
Some(bootstrap_height),
|
||||
@ -1227,8 +1220,12 @@ fn test_full_leader_validator_network() {
|
||||
}
|
||||
|
||||
// Make a common mint and a genesis entry for both leader + validator's ledgers
|
||||
let (mint, bootstrap_leader_ledger_path, genesis_entries) =
|
||||
create_tmp_sample_ledger("test_full_leader_validator_network", 10_000);
|
||||
let num_ending_ticks = 1;
|
||||
let (mint, bootstrap_leader_ledger_path, genesis_entries) = create_tmp_sample_ledger(
|
||||
"test_full_leader_validator_network",
|
||||
10_000,
|
||||
num_ending_ticks,
|
||||
);
|
||||
|
||||
let last_tick_id = genesis_entries
|
||||
.last()
|
||||
@ -1251,8 +1248,13 @@ fn test_full_leader_validator_network() {
|
||||
for node_keypair in node_keypairs.iter() {
|
||||
// Make entries to give the validator some stake so that he will be in
|
||||
// leader election active set
|
||||
let bootstrap_entries =
|
||||
make_active_set_entries(node_keypair, &mint.keypair(), &last_entry_id, &last_tick_id);
|
||||
let bootstrap_entries = make_active_set_entries(
|
||||
node_keypair,
|
||||
&mint.keypair(),
|
||||
&last_entry_id,
|
||||
&last_tick_id,
|
||||
0,
|
||||
);
|
||||
|
||||
// Write the entries
|
||||
let mut ledger_writer = LedgerWriter::open(&bootstrap_leader_ledger_path, false).unwrap();
|
||||
|
Reference in New Issue
Block a user