Skip to content

Commit 932a77f

Browse files
committed
test(core): Test insert displaces conflicting blocks
1 parent 9ce0bd6 commit 932a77f

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

crates/core/src/checkpoint.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ impl<D> IntoIterator for CheckPoint<D> {
364364
mod tests {
365365
use super::*;
366366

367+
use alloc::vec::Vec;
368+
use bitcoin::consensus::encode::deserialize_hex;
369+
use bitcoin::hashes::Hash;
370+
367371
/// Make sure that dropping checkpoints does not result in recursion and stack overflow.
368372
#[test]
369373
fn checkpoint_drop_is_not_recursive() {
@@ -422,4 +426,100 @@ mod tests {
422426
"the checkpoint node should be freed when all strong references are dropped",
423427
);
424428
}
429+
430+
#[test]
431+
fn insert_displaces_conflicting_block() {
432+
let headers: Vec<Header> = [
433+
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2002000000",
434+
"0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1c96cc459dbb0c7bbc722af14f913da868779290ad48ff87ee314ebb8ae08f384b166069ffff7f2001000000",
435+
"0000002078ce518c7dcfd99ad5859c35bd2be15794c0e5dc8e60c1fea3b0461c45da181ca80f828504f88c645ea46cfcf93156269807e3bd409e1317271a1546d238e9b24c166069ffff7f2001000000",
436+
"000000200dfd6c5af6ea3cb341a08db344f93743d94b630d122867faff855f6310e58864e6e0c859fda703d66d051b86f16f09b0cead182f3cbe13767cd91b6371ec252c4c166069ffff7f2000000000",
437+
]
438+
.into_iter()
439+
.map(|s| deserialize_hex::<Header>(s).expect("failed to deserialize header"))
440+
.collect();
441+
442+
let header_0 = headers[0];
443+
let header_1 = headers[1];
444+
let header_2 = headers[2];
445+
let header_3 = headers[3];
446+
447+
// Test: Insert 2' that conflicts at heights 1, 2.
448+
// tip [0, 1, 2, 3]
449+
// insert [1', 2']
450+
// new [0, 2'] (1 is displaced, 3 is evicted)
451+
let mut cp = CheckPoint::new(0, header_0);
452+
cp = cp.push(1, header_1).unwrap();
453+
cp = cp.push(2, header_2).unwrap();
454+
cp = cp.push(3, header_3).unwrap();
455+
456+
let mut header_2_alt = header_2;
457+
header_2_alt.prev_blockhash = BlockHash::all_zeros();
458+
cp = cp.insert(2, header_2_alt);
459+
460+
assert_eq!(cp.iter().count(), 2);
461+
assert_eq!(cp.height(), 2);
462+
assert_eq!(cp.hash(), header_2_alt.block_hash());
463+
464+
// Test: Insert 3' that conflicts at height 2
465+
// tip [0, 1, 2]
466+
// insert [2', 3']
467+
// new [0, 1, 3'] (2 is displaced)
468+
let mut cp = CheckPoint::new(0, header_0);
469+
cp = cp.push(1, header_1).unwrap();
470+
cp = cp.push(2, header_2).unwrap();
471+
472+
let mut header_3_alt = header_3;
473+
header_3_alt.prev_blockhash = BlockHash::all_zeros();
474+
cp = cp.insert(3, header_3_alt);
475+
476+
assert_eq!(cp.iter().count(), 3);
477+
assert_eq!(cp.height(), 3);
478+
assert_eq!(cp.hash(), header_3_alt.block_hash());
479+
480+
// Test: Insert 1' that conflicts at height 1
481+
// tip [0, 1, 2, 3]
482+
// insert [1']
483+
// new [0, 1'] (2 and 3 are evicted)
484+
let mut cp = CheckPoint::new(0, header_0);
485+
cp = cp.push(1, header_1).unwrap();
486+
cp = cp.push(2, header_2).unwrap();
487+
cp = cp.push(3, header_3).unwrap();
488+
489+
// Create a conflicting block at height 1 with different hash
490+
// header_2 expects header_1.block_hash() as its prev_blockhash, but we'll insert a
491+
// different block
492+
let mut header_1_alt = header_1;
493+
header_1_alt.nonce = 13;
494+
cp = cp.insert(1, header_1_alt);
495+
496+
// Verify only genesis and the new block at height 1 remain
497+
assert_eq!(cp.iter().count(), 2);
498+
assert_eq!(cp.height(), 1);
499+
assert_eq!(cp.hash(), header_1_alt.block_hash());
500+
}
501+
502+
#[should_panic(expected = "cannot replace the genesis block")]
503+
#[test]
504+
fn insert_should_not_displace_genesis() {
505+
let headers: Vec<Header> = [
506+
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2002000000",
507+
"0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1c96cc459dbb0c7bbc722af14f913da868779290ad48ff87ee314ebb8ae08f384b166069ffff7f2001000000",
508+
"0000002078ce518c7dcfd99ad5859c35bd2be15794c0e5dc8e60c1fea3b0461c45da181ca80f828504f88c645ea46cfcf93156269807e3bd409e1317271a1546d238e9b24c166069ffff7f2001000000",
509+
]
510+
.into_iter()
511+
.map(|s| deserialize_hex::<Header>(s).expect("failed to deserialize header"))
512+
.collect();
513+
514+
let header_0 = headers[0];
515+
let header_1 = headers[1];
516+
let header_2 = headers[2];
517+
518+
// Test: Insert 1' that conflicts at heights 0, 1.
519+
// tip [0, 1]
520+
// insert [0', 1']
521+
let mut cp = CheckPoint::new(0, header_0);
522+
cp = cp.push(1, header_1).unwrap();
523+
let _cp = cp.insert(1, header_2);
524+
}
425525
}

0 commit comments

Comments
 (0)