Skip to content

Commit 8fc4764

Browse files
committed
Generate PoW-compliant headers for lightning-block-sync tests
The previous values were non-sensical for the compact target representation, and it's nice to test with valid PoW chains anyway.
1 parent 510522d commit 8fc4764

File tree

3 files changed

+76
-50
lines changed

3 files changed

+76
-50
lines changed

lightning-block-sync/src/lib.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ mod spv_client_tests {
447447
let mut chain = Blockchain::default().with_height(3).without_headers();
448448
let best_tip = chain.at_height(1);
449449

450-
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
450+
let poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
451451
let mut cache = UnboundedCache::new();
452452
let mut listener = NullChainListener {};
453453
let mut client = SpvClient::new(best_tip, poller, &mut cache, &mut listener);
@@ -466,7 +466,7 @@ mod spv_client_tests {
466466
let mut chain = Blockchain::default().with_height(3);
467467
let common_tip = chain.tip();
468468

469-
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
469+
let poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
470470
let mut cache = UnboundedCache::new();
471471
let mut listener = NullChainListener {};
472472
let mut client = SpvClient::new(common_tip, poller, &mut cache, &mut listener);
@@ -486,7 +486,7 @@ mod spv_client_tests {
486486
let new_tip = chain.tip();
487487
let old_tip = chain.at_height(1);
488488

489-
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
489+
let poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
490490
let mut cache = UnboundedCache::new();
491491
let mut listener = NullChainListener {};
492492
let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener);
@@ -506,7 +506,7 @@ mod spv_client_tests {
506506
let new_tip = chain.tip();
507507
let old_tip = chain.at_height(1);
508508

509-
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
509+
let poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
510510
let mut cache = UnboundedCache::new();
511511
let mut listener = NullChainListener {};
512512
let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener);
@@ -526,7 +526,7 @@ mod spv_client_tests {
526526
let new_tip = chain.tip();
527527
let old_tip = chain.at_height(1);
528528

529-
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
529+
let poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
530530
let mut cache = UnboundedCache::new();
531531
let mut listener = NullChainListener {};
532532
let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener);
@@ -547,7 +547,7 @@ mod spv_client_tests {
547547
chain.disconnect_tip();
548548
let worse_tip = chain.tip();
549549

550-
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
550+
let poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
551551
let mut cache = UnboundedCache::new();
552552
let mut listener = NullChainListener {};
553553
let mut client = SpvClient::new(best_tip, poller, &mut cache, &mut listener);
@@ -582,7 +582,7 @@ mod chain_notifier_tests {
582582
header_cache: &mut chain.header_cache(0..=1),
583583
chain_listener,
584584
};
585-
let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
585+
let mut poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
586586
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
587587
Err((e, _)) => panic!("Unexpected error: {:?}", e),
588588
Ok(_) => {},
@@ -591,17 +591,17 @@ mod chain_notifier_tests {
591591

592592
#[tokio::test]
593593
async fn sync_from_different_chains() {
594-
let mut test_chain = Blockchain::with_network(Network::Testnet).with_height(1);
595-
let main_chain = Blockchain::with_network(Network::Bitcoin).with_height(1);
594+
let mut chain_1 = Blockchain::with_network(Network::Regtest).with_height(1);
595+
let chain_2 = Blockchain::with_different_genesis_block(Network::Regtest).with_height(1);
596596

597-
let new_tip = test_chain.tip();
598-
let old_tip = main_chain.tip();
597+
let new_tip = chain_1.tip();
598+
let old_tip = chain_2.tip();
599599
let chain_listener = &MockChainListener::new();
600600
let mut notifier = ChainNotifier {
601-
header_cache: &mut main_chain.header_cache(0..=1),
601+
header_cache: &mut chain_2.header_cache(0..=1),
602602
chain_listener,
603603
};
604-
let mut poller = poll::ChainPoller::new(&mut test_chain, Network::Testnet);
604+
let mut poller = poll::ChainPoller::new(&mut chain_1, Network::Regtest);
605605
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
606606
Err((e, _)) => {
607607
assert_eq!(e.kind(), BlockSourceErrorKind::Persistent);
@@ -625,7 +625,7 @@ mod chain_notifier_tests {
625625
header_cache: &mut main_chain.header_cache(0..=2),
626626
chain_listener,
627627
};
628-
let mut poller = poll::ChainPoller::new(&mut fork_chain, Network::Testnet);
628+
let mut poller = poll::ChainPoller::new(&mut fork_chain, Network::Regtest);
629629
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
630630
Err((e, _)) => panic!("Unexpected error: {:?}", e),
631631
Ok(_) => {},
@@ -648,7 +648,7 @@ mod chain_notifier_tests {
648648
header_cache: &mut main_chain.header_cache(0..=3),
649649
chain_listener,
650650
};
651-
let mut poller = poll::ChainPoller::new(&mut fork_chain, Network::Testnet);
651+
let mut poller = poll::ChainPoller::new(&mut fork_chain, Network::Regtest);
652652
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
653653
Err((e, _)) => panic!("Unexpected error: {:?}", e),
654654
Ok(_) => {},
@@ -671,7 +671,7 @@ mod chain_notifier_tests {
671671
header_cache: &mut main_chain.header_cache(0..=2),
672672
chain_listener,
673673
};
674-
let mut poller = poll::ChainPoller::new(&mut fork_chain, Network::Testnet);
674+
let mut poller = poll::ChainPoller::new(&mut fork_chain, Network::Regtest);
675675
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
676676
Err((e, _)) => panic!("Unexpected error: {:?}", e),
677677
Ok(_) => {},
@@ -689,7 +689,7 @@ mod chain_notifier_tests {
689689
header_cache: &mut chain.header_cache(0..=1),
690690
chain_listener,
691691
};
692-
let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
692+
let mut poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
693693
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
694694
Err((_, tip)) => assert_eq!(tip, None),
695695
Ok(_) => panic!("Expected error"),
@@ -707,7 +707,7 @@ mod chain_notifier_tests {
707707
header_cache: &mut chain.header_cache(0..=3),
708708
chain_listener,
709709
};
710-
let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
710+
let mut poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
711711
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
712712
Err((_, tip)) => assert_eq!(tip, Some(old_tip)),
713713
Ok(_) => panic!("Expected error"),
@@ -726,7 +726,7 @@ mod chain_notifier_tests {
726726
header_cache: &mut chain.header_cache(0..=3),
727727
chain_listener,
728728
};
729-
let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
729+
let mut poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
730730
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
731731
Err((_, tip)) => assert_eq!(tip, Some(chain.at_height(2))),
732732
Ok(_) => panic!("Expected error"),
@@ -746,7 +746,7 @@ mod chain_notifier_tests {
746746
header_cache: &mut chain.header_cache(0..=1),
747747
chain_listener,
748748
};
749-
let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
749+
let mut poller = poll::ChainPoller::new(&mut chain, Network::Regtest);
750750
match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
751751
Err((e, _)) => panic!("Unexpected error: {:?}", e),
752752
Ok(_) => {},

lightning-block-sync/src/poll.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ impl<B: Deref<Target=T> + Sized + Send + Sync, T: BlockSource + ?Sized> Poll for
260260
#[cfg(test)]
261261
mod tests {
262262
use crate::*;
263-
use crate::test_utils::Blockchain;
263+
use crate::test_utils::*;
264264
use super::*;
265265
use bitcoin::pow::Work;
266266

@@ -270,7 +270,7 @@ mod tests {
270270
let best_known_chain_tip = chain.tip();
271271
chain.disconnect_tip();
272272

273-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
273+
let poller = ChainPoller::new(&chain, Network::Regtest);
274274
match poller.poll_chain_tip(best_known_chain_tip).await {
275275
Err(e) => {
276276
assert_eq!(e.kind(), BlockSourceErrorKind::Transient);
@@ -285,7 +285,7 @@ mod tests {
285285
let chain = Blockchain::default().with_height(1).without_headers();
286286
let best_known_chain_tip = chain.at_height(0);
287287

288-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
288+
let poller = ChainPoller::new(&chain, Network::Regtest);
289289
match poller.poll_chain_tip(best_known_chain_tip).await {
290290
Err(e) => {
291291
assert_eq!(e.kind(), BlockSourceErrorKind::Persistent);
@@ -301,9 +301,9 @@ mod tests {
301301
let best_known_chain_tip = chain.at_height(0);
302302

303303
// Invalidate the tip by changing its target.
304-
chain.blocks.last_mut().unwrap().header.bits = Target::from_be_bytes([0; 32]).to_compact_lossy();
304+
chain.blocks.last_mut().unwrap().header.bits = Work::MAINNET_MIN.to_target().to_compact_lossy();
305305

306-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
306+
let poller = ChainPoller::new(&chain, Network::Regtest);
307307
match poller.poll_chain_tip(best_known_chain_tip).await {
308308
Err(e) => {
309309
assert_eq!(e.kind(), BlockSourceErrorKind::Persistent);
@@ -318,7 +318,7 @@ mod tests {
318318
let chain = Blockchain::default().with_height(1).malformed_headers();
319319
let best_known_chain_tip = chain.at_height(0);
320320

321-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
321+
let poller = ChainPoller::new(&chain, Network::Regtest);
322322
match poller.poll_chain_tip(best_known_chain_tip).await {
323323
Err(e) => {
324324
assert_eq!(e.kind(), BlockSourceErrorKind::Persistent);
@@ -333,7 +333,7 @@ mod tests {
333333
let chain = Blockchain::default().with_height(0);
334334
let best_known_chain_tip = chain.tip();
335335

336-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
336+
let poller = ChainPoller::new(&chain, Network::Regtest);
337337
match poller.poll_chain_tip(best_known_chain_tip).await {
338338
Err(e) => panic!("Unexpected error: {:?}", e),
339339
Ok(tip) => assert_eq!(tip, ChainTip::Common),
@@ -345,12 +345,14 @@ mod tests {
345345
let mut chain = Blockchain::default().with_height(1);
346346
let best_known_chain_tip = chain.tip();
347347

348-
// Change the nonce to get a different block hash with the same chainwork.
349-
chain.blocks.last_mut().unwrap().header.nonce += 1;
348+
// Change the header to get a lower target block hash with the same chainwork.
349+
let current_target = best_known_chain_tip.header.target();
350+
let worse_target = current_target.min_difficulty_transition_threshold();
351+
generate_pow_compliant_header(&worse_target, &mut chain.blocks.last_mut().unwrap().header);
350352
let worse_chain_tip = chain.tip();
351353
assert_eq!(best_known_chain_tip.chainwork, worse_chain_tip.chainwork);
352354

353-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
355+
let poller = ChainPoller::new(&chain, Network::Regtest);
354356
match poller.poll_chain_tip(best_known_chain_tip).await {
355357
Err(e) => panic!("Unexpected error: {:?}", e),
356358
Ok(tip) => assert_eq!(tip, ChainTip::Worse(worse_chain_tip)),
@@ -365,7 +367,7 @@ mod tests {
365367
chain.disconnect_tip();
366368
let worse_chain_tip = chain.tip();
367369

368-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
370+
let poller = ChainPoller::new(&chain, Network::Regtest);
369371
match poller.poll_chain_tip(best_known_chain_tip).await {
370372
Err(e) => panic!("Unexpected error: {:?}", e),
371373
Ok(tip) => assert_eq!(tip, ChainTip::Worse(worse_chain_tip)),
@@ -379,7 +381,7 @@ mod tests {
379381

380382
let better_chain_tip = chain.tip();
381383

382-
let poller = ChainPoller::new(&chain, Network::Bitcoin);
384+
let poller = ChainPoller::new(&chain, Network::Regtest);
383385
match poller.poll_chain_tip(best_known_chain_tip).await {
384386
Err(e) => panic!("Unexpected error: {:?}", e),
385387
Ok(tip) => assert_eq!(tip, ChainTip::Better(better_chain_tip)),

lightning-block-sync/src/test_utils.rs

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ use bitcoin::blockdata::constants::genesis_block;
66
use bitcoin::blockdata::locktime::absolute::LockTime;
77
use bitcoin::hash_types::{BlockHash, TxMerkleNode};
88
use bitcoin::network::constants::Network;
9-
use bitcoin::pow::Work;
10-
use bitcoin::Transaction;
9+
use bitcoin::{Target, Transaction};
1110

1211
use lightning::chain;
1312

@@ -23,23 +22,44 @@ pub struct Blockchain {
2322
filtered_blocks: bool,
2423
}
2524

25+
pub fn generate_pow_compliant_header(target: &Target, header: &mut Header) {
26+
loop {
27+
if header.nonce == u32::max_value() {
28+
header.nonce = 0;
29+
header.time += 1;
30+
}
31+
header.nonce += 1;
32+
if target.is_met_by(header.block_hash()) {
33+
break;
34+
}
35+
}
36+
}
37+
2638
impl Blockchain {
2739
pub fn default() -> Self {
28-
Blockchain::with_network(Network::Bitcoin)
40+
Blockchain::with_network(Network::Regtest)
2941
}
3042

3143
pub fn with_network(network: Network) -> Self {
3244
let blocks = vec![genesis_block(network)];
3345
Self { blocks, ..Default::default() }
3446
}
3547

48+
pub fn with_different_genesis_block(network: Network) -> Self {
49+
let mut genesis_block = genesis_block(network);
50+
genesis_block.header.nonce += 1;
51+
let blocks = vec![genesis_block];
52+
Self { blocks, ..Default::default() }
53+
}
54+
3655
pub fn with_height(mut self, height: usize) -> Self {
3756
self.blocks.reserve_exact(height);
38-
let bits = Target::from_be_bytes([0xff; 32]).to_compact_lossy();
57+
let genesis_compact_target = self.blocks[0].header.bits;
58+
let genesis_target = Target::from_compact(genesis_compact_target);
3959
for i in 1..=height {
4060
let prev_block = &self.blocks[i - 1];
4161
let prev_blockhash = prev_block.block_hash();
42-
let time = prev_block.header.time + height as u32;
62+
let time = prev_block.header.time + 1;
4363
// Must have at least one transaction, because the merkle root is not defined for an empty block
4464
// and we would fail when we later checked, as of bitcoin crate 0.28.0.
4565
// Note that elsewhere in tests we assume that the merkle root of an empty block is all zeros,
@@ -51,15 +71,17 @@ impl Blockchain {
5171
output: vec![]
5272
};
5373
let merkle_root = TxMerkleNode::from_raw_hash(coinbase.txid().to_raw_hash());
74+
let mut header = Header {
75+
version: Version::NO_SOFT_FORK_SIGNALLING,
76+
prev_blockhash,
77+
merkle_root,
78+
time,
79+
bits: genesis_compact_target,
80+
nonce: 0,
81+
};
82+
generate_pow_compliant_header(&genesis_target, &mut header);
5483
self.blocks.push(Block {
55-
header: Header {
56-
version: Version::NO_SOFT_FORK_SIGNALLING,
57-
prev_blockhash,
58-
merkle_root,
59-
time,
60-
bits,
61-
nonce: 0,
62-
},
84+
header,
6385
txdata: vec![coinbase],
6486
});
6587
}
@@ -88,7 +110,7 @@ impl Blockchain {
88110
let mut prev_blockhash = blocks[height].block_hash();
89111
for block in blocks.iter_mut().skip(height + 1) {
90112
block.header.prev_blockhash = prev_blockhash;
91-
block.header.nonce += 1;
113+
generate_pow_compliant_header(&block.header.target(), &mut block.header);
92114
prev_blockhash = block.block_hash();
93115
}
94116
Self { blocks, without_blocks: None, ..*self }
@@ -103,10 +125,12 @@ impl Blockchain {
103125
fn at_height_unvalidated(&self, height: usize) -> BlockHeaderData {
104126
assert!(!self.blocks.is_empty());
105127
assert!(height < self.blocks.len());
106-
let mut work_bytes = [0; 32];
107-
work_bytes[..8].copy_from_slice(&(height as u64).to_be_bytes());
128+
let mut total_work = self.blocks[0].header.work();
129+
for i in 1..=height {
130+
total_work = total_work + self.blocks[i].header.work();
131+
}
108132
BlockHeaderData {
109-
chainwork: self.blocks[0].header.work() + Work::from_be_bytes(work_bytes),
133+
chainwork: total_work,
110134
height: height as u32,
111135
header: self.blocks[height].header,
112136
}
@@ -143,7 +167,7 @@ impl BlockSource for Blockchain {
143167
if block.header.block_hash() == *header_hash {
144168
let mut header_data = self.at_height_unvalidated(height);
145169
if self.malformed_headers {
146-
header_data.header.time += 1;
170+
generate_pow_compliant_header(&header_data.header.target(), &mut header_data.header);
147171
}
148172

149173
return Ok(header_data);

0 commit comments

Comments
 (0)