Merge pull request #1659 from valentinewallace/2022-08-fix-payload-decode
[rust-lightning] / lightning-block-sync / src / test_utils.rs
index 807a33a69dec3fb305fb56ad9b9dc6953a26b138..0c402deb3294663527afaab0011cea1f627569ef 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{AsyncBlockSourceResult, BlockHeaderData, BlockSource, BlockSourceError, ChainListener, UnboundedCache};
+use crate::{AsyncBlockSourceResult, BlockHeaderData, BlockSource, BlockSourceError, UnboundedCache};
 use crate::poll::{Validate, ValidatedBlockHeader};
 
 use bitcoin::blockdata::block::{Block, BlockHeader};
@@ -6,7 +6,12 @@ use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::hash_types::BlockHash;
 use bitcoin::network::constants::Network;
 use bitcoin::util::uint::Uint256;
+use bitcoin::util::hash::bitcoin_merkle_root;
+use bitcoin::{PackedLockTime, Transaction};
 
+use lightning::chain;
+
+use std::cell::RefCell;
 use std::collections::VecDeque;
 
 #[derive(Default)]
@@ -34,16 +39,27 @@ impl Blockchain {
                        let prev_block = &self.blocks[i - 1];
                        let prev_blockhash = prev_block.block_hash();
                        let time = prev_block.header.time + height as u32;
+                       // Must have at least one transaction, because the merkle root is not defined for an empty block
+                       // and we would fail when we later checked, as of bitcoin crate 0.28.0.
+                       // Note that elsewhere in tests we assume that the merkle root of an empty block is all zeros,
+                       // but that's OK because those tests don't trigger the check.
+                       let coinbase = Transaction {
+                               version: 0,
+                               lock_time: PackedLockTime::ZERO,
+                               input: vec![],
+                               output: vec![]
+                       };
+                       let merkle_root = bitcoin_merkle_root(vec![coinbase.txid().as_hash()].into_iter()).unwrap();
                        self.blocks.push(Block {
                                header: BlockHeader {
                                        version: 0,
                                        prev_blockhash,
-                                       merkle_root: Default::default(),
+                                       merkle_root: merkle_root.into(),
                                        time,
                                        bits,
                                        nonce: 0,
                                },
-                               txdata: vec![],
+                               txdata: vec![coinbase],
                        });
                }
                self
@@ -110,7 +126,7 @@ impl Blockchain {
 }
 
 impl BlockSource for Blockchain {
-       fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, _height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData> {
+       fn get_header<'a>(&'a self, header_hash: &'a BlockHash, _height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData> {
                Box::pin(async move {
                        if self.without_headers {
                                return Err(BlockSourceError::persistent("header not found"));
@@ -130,7 +146,7 @@ impl BlockSource for Blockchain {
                })
        }
 
-       fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
+       fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
                Box::pin(async move {
                        for (height, block) in self.blocks.iter().enumerate() {
                                if block.header.block_hash() == *header_hash {
@@ -147,7 +163,7 @@ impl BlockSource for Blockchain {
                })
        }
 
-       fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<'a, (BlockHash, Option<u32>)> {
+       fn get_best_block<'a>(&'a self) -> AsyncBlockSourceResult<'a, (BlockHash, Option<u32>)> {
                Box::pin(async move {
                        match self.blocks.last() {
                                None => Err(BlockSourceError::transient("empty chain")),
@@ -162,50 +178,50 @@ impl BlockSource for Blockchain {
 
 pub struct NullChainListener;
 
-impl ChainListener for NullChainListener {
-       fn block_connected(&mut self, _block: &Block, _height: u32) {}
-       fn block_disconnected(&mut self, _header: &BlockHeader, _height: u32) {}
+impl chain::Listen for NullChainListener {
+       fn filtered_block_connected(&self, _header: &BlockHeader, _txdata: &chain::transaction::TransactionData, _height: u32) {}
+       fn block_disconnected(&self, _header: &BlockHeader, _height: u32) {}
 }
 
 pub struct MockChainListener {
-       expected_blocks_connected: VecDeque<BlockHeaderData>,
-       expected_blocks_disconnected: VecDeque<BlockHeaderData>,
+       expected_blocks_connected: RefCell<VecDeque<BlockHeaderData>>,
+       expected_blocks_disconnected: RefCell<VecDeque<BlockHeaderData>>,
 }
 
 impl MockChainListener {
        pub fn new() -> Self {
                Self {
-                       expected_blocks_connected: VecDeque::new(),
-                       expected_blocks_disconnected: VecDeque::new(),
+                       expected_blocks_connected: RefCell::new(VecDeque::new()),
+                       expected_blocks_disconnected: RefCell::new(VecDeque::new()),
                }
        }
 
-       pub fn expect_block_connected(mut self, block: BlockHeaderData) -> Self {
-               self.expected_blocks_connected.push_back(block);
+       pub fn expect_block_connected(self, block: BlockHeaderData) -> Self {
+               self.expected_blocks_connected.borrow_mut().push_back(block);
                self
        }
 
-       pub fn expect_block_disconnected(mut self, block: BlockHeaderData) -> Self {
-               self.expected_blocks_disconnected.push_back(block);
+       pub fn expect_block_disconnected(self, block: BlockHeaderData) -> Self {
+               self.expected_blocks_disconnected.borrow_mut().push_back(block);
                self
        }
 }
 
-impl ChainListener for MockChainListener {
-       fn block_connected(&mut self, block: &Block, height: u32) {
-               match self.expected_blocks_connected.pop_front() {
+impl chain::Listen for MockChainListener {
+       fn filtered_block_connected(&self, header: &BlockHeader, _txdata: &chain::transaction::TransactionData, height: u32) {
+               match self.expected_blocks_connected.borrow_mut().pop_front() {
                        None => {
-                               panic!("Unexpected block connected: {:?}", block.block_hash());
+                               panic!("Unexpected block connected: {:?}", header.block_hash());
                        },
                        Some(expected_block) => {
-                               assert_eq!(block.block_hash(), expected_block.header.block_hash());
+                               assert_eq!(header.block_hash(), expected_block.header.block_hash());
                                assert_eq!(height, expected_block.height);
                        },
                }
        }
 
-       fn block_disconnected(&mut self, header: &BlockHeader, height: u32) {
-               match self.expected_blocks_disconnected.pop_front() {
+       fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+               match self.expected_blocks_disconnected.borrow_mut().pop_front() {
                        None => {
                                panic!("Unexpected block disconnected: {:?}", header.block_hash());
                        },
@@ -222,11 +238,15 @@ impl Drop for MockChainListener {
                if std::thread::panicking() {
                        return;
                }
-               if !self.expected_blocks_connected.is_empty() {
-                       panic!("Expected blocks connected: {:?}", self.expected_blocks_connected);
+
+               let expected_blocks_connected = self.expected_blocks_connected.borrow();
+               if !expected_blocks_connected.is_empty() {
+                       panic!("Expected blocks connected: {:?}", expected_blocks_connected);
                }
-               if !self.expected_blocks_disconnected.is_empty() {
-                       panic!("Expected blocks disconnected: {:?}", self.expected_blocks_disconnected);
+
+               let expected_blocks_disconnected = self.expected_blocks_disconnected.borrow();
+               if !expected_blocks_disconnected.is_empty() {
+                       panic!("Expected blocks disconnected: {:?}", expected_blocks_disconnected);
                }
        }
 }