Skip to content

Commit

Permalink
Add more rebranch tests to light blockchain
Browse files Browse the repository at this point in the history
  • Loading branch information
viquezclaudio committed Jan 9, 2023
1 parent 2313e65 commit 223870b
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 20 deletions.
11 changes: 4 additions & 7 deletions light-blockchain/src/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,6 @@ impl LightBlockchain {
this: RwLockUpgradableReadGuard<Self>,
chain_info: ChainInfo,
) -> Result<PushResult, PushError> {
// You can't rebranch a macro block.
assert!(chain_info.head.is_micro());

// Upgrade the blockchain lock
let mut this = RwLockUpgradableReadGuard::upgrade_untimed(this);

Expand Down Expand Up @@ -214,7 +211,7 @@ impl LightBlockchain {
"Found common ancestor",
);

// Revert AccountsTree & TransactionCache to the common ancestor state.
// Revert to the common ancestor.
let mut revert_chain: Vec<(Blake2bHash, ChainInfo)> = vec![];
let mut ancestor = current;

Expand Down Expand Up @@ -252,19 +249,19 @@ impl LightBlockchain {
current = (prev_hash, prev_info);
}

// Unset onMainChain flag / mainChainSuccessor on the current main chain up to (excluding) the common ancestor.
// Unset on_main_chain flag / main_chain_successor on the current main chain up to (excluding) the common ancestor.
for reverted_block in revert_chain.iter_mut() {
reverted_block.1.on_main_chain = false;
reverted_block.1.main_chain_successor = None;

this.chain_store.put_chain_info(reverted_block.1.clone());
}

// Update the mainChainSuccessor of the common ancestor block.
// Update the main_chain_successor of the common ancestor block.
ancestor.1.main_chain_successor = Some(fork_chain.last().unwrap().0.clone());
this.chain_store.put_chain_info(ancestor.1);

// Set onMainChain flag / mainChainSuccessor on the fork.
// Set on_main_chain flag / main_chain_successor on the fork.
for i in (0..fork_chain.len()).rev() {
let main_chain_successor = if i > 0 {
Some(fork_chain[i - 1].0.clone())
Expand Down
106 changes: 93 additions & 13 deletions light-blockchain/tests/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,11 @@ fn it_can_rebranch_skip_block() {
fn micro_block_works_after_macro_block() {
let temp_producer = TemporaryLightBlockProducer::new();

// apply an entire batch including macro block on view_number/round_number zero
// Apply an entire batch including macro block on skip_block/round_number zero
for _ in 0..Policy::blocks_per_batch() {
temp_producer.next_block(vec![], false);
}
// make sure we are at the beginning of the batch and all block were applied
// Make sure we are at the beginning of the batch and all block were applied
assert_eq!(
temp_producer.blockchain.read().block_number(),
Policy::blocks_per_batch()
Expand All @@ -460,29 +460,29 @@ fn micro_block_works_after_macro_block() {
// Test if a micro block can be rebranched immediately after
// a round_number 0 macro block

// create a couple of skip blocks
// Create a couple of skip blocks
let block = temp_producer.next_block_no_push(vec![], true);
let rebranch = temp_producer.next_block_no_push(vec![], true);
// push first skip block
// Push first skip block
temp_producer.push(block).unwrap();
// make sure this was an extend
// Make sure this was an extend
assert_eq!(
temp_producer.blockchain.read().block_number(),
Policy::blocks_per_batch() + 1
);
// and rebranch it to block the chain with only one skip block
// And rebranch it to block the chain with only one skip block
temp_producer.push(rebranch).unwrap();
// make sure this was a rebranch
// Make sure this was a rebranch
assert_eq!(
temp_producer.blockchain.read().block_number(),
Policy::blocks_per_batch() + 1
);

// apply the rest of the batch including macro block on view_number/round_number one
// Apply the rest of the batch including macro block on round_number one
for _ in 0..Policy::blocks_per_batch() - 1 {
temp_producer.next_block(vec![], false);
}
// make sure we are at the beginning of the batch
// Make sure we are at the beginning of the batch
assert_eq!(
temp_producer.blockchain.read().block_number(),
Policy::blocks_per_batch() * 2
Expand All @@ -491,14 +491,13 @@ fn micro_block_works_after_macro_block() {
// Test if a micro block can be rebranched immediately after
// a round_number non 0 macro block

// create blocks for a chain with accumulated skip blocks after the batch of 0, 1 and 2
// Create blocks for a chain with accumulated skip blocks after the batch of 0, 1 and 2
let block = temp_producer.next_block_no_push(vec![], true);
let rebranch1 = temp_producer.next_block_no_push(vec![], true);
// let rebranch2 = temp_producer.next_block_no_push(2, vec![]);
// apply them each rebranching the previous one

// Apply them each rebranching the previous one
temp_producer.push(block).unwrap();
temp_producer.push(rebranch1).unwrap();
// temp_producer.push(rebranch2).unwrap();

assert_eq!(
temp_producer.blockchain.read().block_number(),
Expand Down Expand Up @@ -543,3 +542,84 @@ fn it_can_rebranch_forks() {
assert_eq!(temp_producer1.push(fork2d), Ok(PushResult::Extended));
assert_eq!(temp_producer2.push(fork1d), Ok(PushResult::Ignored));
}

#[test]
fn it_can_rebranch_at_macro_block() {
// Build forks using two producers.
let temp_producer1 = TemporaryLightBlockProducer::new();
let temp_producer2 = TemporaryLightBlockProducer::new();

// The numbers in [X/Y] represent block_number (X) and accumulated number of skip blocks (Y):
//
// [0/0] ... [1/0] - [1/0]
// \- [1/1]

let mut block;
loop {
block = temp_producer1.next_block(vec![], false);
temp_producer2.push(block.clone()).unwrap();
if block.is_macro() {
break;
}
}

let fork1 = temp_producer1.next_block(vec![], false);
let fork2 = temp_producer2.next_block(vec![], true);

assert_eq!(temp_producer1.push(fork2), Ok(PushResult::Rebranched));
assert_eq!(temp_producer2.push(fork1), Ok(PushResult::Ignored));
}

#[test]
fn it_can_rebranch_to_inferior_macro_block() {
// Build forks using two producers.
let producer1 = TemporaryLightBlockProducer::new();
let producer2 = TemporaryLightBlockProducer::new();

// (1 denotes a skip block)
// [0] - [0] - ... - [0] - [macro 0]
// \- [1] - ... - [0]

// Do one iteration first to create fork
let inferior = producer1.next_block(vec![], false);
producer2.next_block(vec![], true);
assert_eq!(producer2.push(inferior), Ok(PushResult::Ignored));

// Complete a batch
for _ in 1..Policy::blocks_per_batch() - 1 {
let inferior = producer1.next_block(vec![], false);
producer2.next_block(vec![], false);
assert_eq!(producer2.push(inferior), Ok(PushResult::Ignored));
}

let macro_block = producer1.next_block(vec![], false);
assert!(macro_block.is_macro());

// Check that producer 2 rebranches.
assert_eq!(producer2.push(macro_block), Ok(PushResult::Rebranched));

// Push one additional block and check that producer 2 accepts it.
let block = producer1.next_block(vec![], false);
assert_eq!(producer2.push(block), Ok(PushResult::Extended));

// Check that both chains are in an identical state.
let blockchain1 = producer1.blockchain.read();
let blockchain2 = producer2.blockchain.read();
assert_eq!(blockchain1.state.head_hash, blockchain2.state.head_hash);
assert_eq!(
blockchain1.state.macro_head_hash,
blockchain2.state.macro_head_hash
);
assert_eq!(
blockchain1.state.election_head_hash,
blockchain2.state.election_head_hash
);
assert_eq!(
blockchain1.state.current_slots,
blockchain2.state.current_slots
);
assert_eq!(
blockchain1.state.previous_slots,
blockchain2.state.previous_slots
);
}

0 comments on commit 223870b

Please sign in to comment.