slot 0 now contains the same number of ticks as all subsequent slots

This commit is contained in:
Michael Vines
2019-02-10 09:38:09 -08:00
parent 4b38ecd916
commit 7dec40ff05
9 changed files with 202 additions and 153 deletions

View File

@@ -817,25 +817,40 @@ impl Bank {
where
I: IntoIterator<Item = Entry>,
{
let mut entry_height = 0;
let mut last_id = self.last_id();
let mut last_entry_id = self.last_id();
let mut entries_iter = entries.into_iter();
trace!("genesis last_id={}", last_entry_id);
// 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
let entry0 = entries_iter
.next()
.ok_or(BankError::LedgerVerificationFailed)?;
if !(entry0.is_tick() && entry0.verify(&last_entry_id)) {
warn!("Ledger proof of history failed at entry0");
return Err(BankError::LedgerVerificationFailed);
}
last_entry_id = entry0.id;
let mut entry_height = 1;
// Ledger verification needs to be parallelized, but we can't pull the whole
// thing into memory. We therefore chunk it.
for block in &entries.into_iter().chunks(VERIFY_BLOCK_SIZE) {
for block in &entries_iter.chunks(VERIFY_BLOCK_SIZE) {
let block: Vec<_> = block.collect();
if !block.verify(&last_id) {
if !block.verify(&last_entry_id) {
warn!("Ledger proof of history failed at entry: {}", entry_height);
return Err(BankError::LedgerVerificationFailed);
}
self.process_block(&block)?;
last_id = block.last().unwrap().id;
last_entry_id = block.last().unwrap().id;
entry_height += block.len() as u64;
}
Ok((entry_height, last_id))
Ok((entry_height, last_entry_id))
}
/// Create, sign, and process a Transaction from `keypair` to `to` of
@@ -1251,10 +1266,12 @@ mod tests {
) -> impl Iterator<Item = Entry> {
let mut entries: Vec<Entry> = vec![];
// Start off the ledger with a tick linked to the genesis block
let mut last_id = genesis_block.last_id();
// Start off the ledger with the psuedo-tick linked to the genesis block
// (see entry0 in `process_ledger`)
let tick = Entry::new(&genesis_block.last_id(), 0, 1, vec![]);
let mut hash = tick.id;
let mut last_id = tick.id;
entries.push(tick);
let num_hashes = 1;
@@ -1281,10 +1298,12 @@ mod tests {
) -> impl Iterator<Item = Entry> {
let mut entries = vec![];
// Start off the ledger with a tick linked to the genesis block
let mut last_id = genesis_block.last_id();
// Start off the ledger with the psuedo-tick linked to the genesis block
// (see entry0 in `process_ledger`)
let tick = Entry::new(&genesis_block.last_id(), 0, 1, vec![]);
let mut hash = tick.id;
let mut last_id = tick.id;
entries.push(tick);
for i in 0..num_one_token_transfers {
@@ -1351,7 +1370,7 @@ mod tests {
let (ledger_height, last_id) = bank.process_ledger(ledger).unwrap();
assert_eq!(bank.get_balance(&mint_keypair.pubkey()), 100 - 3);
assert_eq!(ledger_height, 8);
assert_eq!(bank.tick_height(), 2);
assert_eq!(bank.tick_height(), 1);
assert_eq!(bank.last_id(), last_id);
}

View File

@@ -150,15 +150,7 @@ impl SlotMeta {
// A placeholder slot does not contain all the ticks
false
} else {
let num_expected_ticks = {
let num = self.num_expected_ticks(blocktree);
if self.slot_height == 0 {
num - 1
} else {
num
}
};
num_expected_ticks <= self.consumed_ticks
self.num_expected_ticks(blocktree) <= self.consumed_ticks
}
}
@@ -1305,35 +1297,38 @@ pub fn get_tmp_ledger_path(name: &str) -> String {
path
}
pub fn create_tmp_ledger(name: &str, genesis_block: &GenesisBlock) -> String {
let ledger_path = get_tmp_ledger_path(name);
create_new_ledger(&ledger_path, genesis_block).unwrap();
ledger_path
}
pub fn create_tmp_sample_ledger(
name: &str,
num_tokens: u64,
num_extra_ticks: u64,
bootstrap_leader_id: Pubkey,
bootstrap_leader_tokens: u64,
) -> (Keypair, String, u64, Hash) {
) -> (Keypair, String, u64, Hash, Hash) {
let (genesis_block, mint_keypair) =
GenesisBlock::new_with_leader(num_tokens, bootstrap_leader_id, bootstrap_leader_tokens);
let ledger_path = get_tmp_ledger_path(name);
let (mut entry_height, mut last_id) = create_new_ledger(&ledger_path, &genesis_block).unwrap();
let (mut entry_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_id);
let entries = crate::entry::create_ticks(num_extra_ticks, last_entry_id);
let blocktree = Blocktree::open(&ledger_path).unwrap();
blocktree
.write_entries(DEFAULT_SLOT_HEIGHT, entry_height, &entries)
.unwrap();
entry_height += entries.len() as u64;
last_id = entries.last().unwrap().id
last_id = entries.last().unwrap().id;
last_entry_id = last_id;
}
(mint_keypair, ledger_path, entry_height, last_id)
(
mint_keypair,
ledger_path,
entry_height,
last_id,
last_entry_id,
)
}
pub fn tmp_copy_ledger(from: &str, name: &str) -> String {
@@ -1992,11 +1987,7 @@ mod tests {
assert_eq!(s.next_slots, vec![i + 1]);
}
assert_eq!(s.num_blocks, 1);
if i == 0 {
assert_eq!(s.consumed_ticks, ticks_per_slot - 1);
} else {
assert_eq!(s.consumed_ticks, ticks_per_slot);
}
assert_eq!(s.consumed_ticks, ticks_per_slot);
assert!(s.is_trunk);
}
}
@@ -2062,11 +2053,7 @@ mod tests {
} else {
assert!(s.next_slots.is_empty());
}
if i == 0 {
assert_eq!(s.consumed_ticks, ticks_per_slot - 1);
} else {
assert_eq!(s.consumed_ticks, ticks_per_slot);
}
assert_eq!(s.consumed_ticks, ticks_per_slot);
assert!(s.is_trunk);
}
}

View File

@@ -580,7 +580,7 @@ mod tests {
let validator_keypair = Keypair::new();
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
let (_, validator_ledger_path, _, _) =
let (_mint_keypair, validator_ledger_path, _last_entry_height, _last_id, _last_entry_id) =
create_tmp_sample_ledger("validator_exit", 10_000, 0, leader_keypair.pubkey(), 1000);
let validator = Fullnode::new(
@@ -605,7 +605,13 @@ mod tests {
.map(|i| {
let validator_keypair = Keypair::new();
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
let (_, validator_ledger_path, _, _) = create_tmp_sample_ledger(
let (
_mint_keypair,
validator_ledger_path,
_last_entry_height,
_last_id,
_last_entry_id,
) = create_tmp_sample_ledger(
&format!("validator_parallel_exit_{}", i),
10_000,
0,
@@ -645,14 +651,19 @@ mod tests {
let bootstrap_leader_node =
Node::new_localhost_with_pubkey(bootstrap_leader_keypair.pubkey());
let (_mint_keypair, bootstrap_leader_ledger_path, _genesis_entry_height, _last_id) =
create_tmp_sample_ledger(
"test_leader_to_leader_transition",
10_000,
1,
bootstrap_leader_keypair.pubkey(),
500,
);
let (
_mint_keypair,
bootstrap_leader_ledger_path,
_genesis_entry_height,
_last_id,
_last_entry_id,
) = create_tmp_sample_ledger(
"test_leader_to_leader_transition",
10_000,
1,
bootstrap_leader_keypair.pubkey(),
500,
);
// Once the bootstrap leader hits the second epoch, because there are no other choices in
// the active set, this leader will remain the leader in the second epoch. In the second
@@ -1018,13 +1029,14 @@ mod tests {
// Create validator identity
assert!(num_genesis_ticks <= ticks_per_block);
let (mint_keypair, ledger_path, genesis_entry_height, last_id) = create_tmp_sample_ledger(
test_name,
10_000,
num_genesis_ticks,
leader_node.info.id,
500,
);
let (mint_keypair, ledger_path, genesis_entry_height, last_id, last_entry_id) =
create_tmp_sample_ledger(
test_name,
10_000,
num_genesis_ticks,
leader_node.info.id,
500,
);
let validator_node = Node::new_localhost_with_pubkey(validator_keypair.pubkey());
@@ -1040,7 +1052,7 @@ mod tests {
&mint_keypair,
10,
1,
&last_id,
&last_entry_id,
&last_id,
num_ending_ticks,
);

View File

@@ -87,6 +87,7 @@ impl ReplayStage {
let mut res = Ok(());
let mut num_entries_to_write = entries.len();
let now = Instant::now();
if !entries.as_slice().verify(&last_entry_id.read().unwrap()) {
inc_new_counter_info!("replicate_stage-verify-fail", entries.len());
return Err(Error::BlobError(BlobError::VerificationFailed));
@@ -411,7 +412,7 @@ mod test {
let old_leader_id = Keypair::new().pubkey();
// Create a ledger
let (mint_keypair, my_ledger_path, genesis_entry_height, mut last_id) =
let (mint_keypair, my_ledger_path, genesis_entry_height, mut last_id, last_entry_id) =
create_tmp_sample_ledger(
"test_replay_stage_leader_rotation_exit",
10_000,
@@ -433,7 +434,7 @@ mod test {
&mint_keypair,
100,
ticks_per_slot, // add a vote for tick_height = ticks_per_slot
&last_id,
&last_entry_id,
&last_id,
0,
);
@@ -538,13 +539,14 @@ mod test {
// Create keypair for the leader
let leader_id = Keypair::new().pubkey();
let (_, my_ledger_path, _, _) = create_tmp_sample_ledger(
"test_vote_error_replay_stage_correctness",
10_000,
1,
leader_id,
500,
);
let (_mint_keypair, my_ledger_path, _last_entry_height, _last_id, _last_entry_id) =
create_tmp_sample_ledger(
"test_vote_error_replay_stage_correctness",
10_000,
1,
leader_id,
500,
);
// Set up the cluster info
let cluster_info_me = Arc::new(RwLock::new(ClusterInfo::new(my_node.info.clone())));
@@ -583,7 +585,7 @@ mod test {
let vote = VoteTransaction::new_vote(keypair, bank.tick_height(), bank.last_id(), 0);
cluster_info_me.write().unwrap().push_vote(vote);
// Send ReplayStage an entry, should see it on the ledger writer receiver
info!("Send ReplayStage an entry, should see it on the ledger writer receiver");
let next_tick = create_ticks(1, last_entry_id);
blocktree
@@ -592,7 +594,7 @@ mod test {
let received_tick = ledger_writer_recv
.recv()
.expect("Expected to recieve an entry on the ledger writer receiver");
.expect("Expected to receive an entry on the ledger writer receiver");
assert_eq!(next_tick, received_tick);
@@ -617,7 +619,7 @@ mod test {
let leader_id = Keypair::new().pubkey();
// Create the ledger
let (mint_keypair, my_ledger_path, genesis_entry_height, last_id) =
let (mint_keypair, my_ledger_path, genesis_entry_height, last_id, last_entry_id) =
create_tmp_sample_ledger(
"test_vote_error_replay_stage_leader_rotation",
10_000,
@@ -630,8 +632,15 @@ mod test {
// 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_id, &last_id, 0);
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 initial_tick_height = genesis_entry_height;

View File

@@ -492,13 +492,14 @@ mod tests {
let keypair = Arc::new(Keypair::new());
let exit = Arc::new(AtomicBool::new(false));
let (_mint, ledger_path, genesis_entry_height, _last_id) = create_tmp_sample_ledger(
"storage_stage_process_entries",
1000,
1,
Keypair::new().pubkey(),
1,
);
let (_mint, ledger_path, genesis_entry_height, _last_id, _last_entry_id) =
create_tmp_sample_ledger(
"storage_stage_process_entries",
1000,
1,
Keypair::new().pubkey(),
1,
);
let entries = make_tiny_test_entries(64);
let blocktree = Blocktree::open(&ledger_path).unwrap();
@@ -560,13 +561,14 @@ mod tests {
let keypair = Arc::new(Keypair::new());
let exit = Arc::new(AtomicBool::new(false));
let (_mint, ledger_path, genesis_entry_height, _last_id) = create_tmp_sample_ledger(
"storage_stage_process_entries",
1000,
1,
Keypair::new().pubkey(),
1,
);
let (_mint, ledger_path, genesis_entry_height, _last_id, _last_entry_id) =
create_tmp_sample_ledger(
"storage_stage_process_entries",
1000,
1,
Keypair::new().pubkey(),
1,
);
let entries = make_tiny_test_entries(128);
let blocktree = Blocktree::open(&ledger_path).unwrap();

View File

@@ -464,7 +464,7 @@ pub fn new_fullnode(ledger_name: &'static str) -> (Fullnode, NodeInfo, Keypair,
let node = Node::new_localhost_with_pubkey(node_keypair.pubkey());
let node_info = node.info.clone();
let (mint_keypair, ledger_path, _, _) =
let (mint_keypair, ledger_path, _last_entry_height, _last_id, _last_entry_id) =
create_tmp_sample_ledger(ledger_name, 10_000, 0, node_info.id, 42);
let vote_account_keypair = Arc::new(Keypair::new());