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:
carllin
2018-10-18 22:57:48 -07:00
committed by GitHub
parent 0339642e77
commit 0bd1412562
28 changed files with 1063 additions and 874 deletions

View File

@ -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();