+
+ /// Sets an expectation that [`chain::Filter::register_output`] is called.
+ pub fn expect(&self, expectation: OnRegisterOutput) -> &Self {
+ self.expectations.lock().unwrap()
+ .get_or_insert_with(|| VecDeque::new())
+ .push_back(expectation);
+ self
+ }
+}
+
+impl chain::Access for TestChainSource {
+ fn get_utxo(&self, genesis_hash: &BlockHash, _short_channel_id: u64) -> Result<TxOut, chain::AccessError> {
+ if self.genesis_hash != *genesis_hash {
+ return Err(chain::AccessError::UnknownChain);
+ }
+
+ self.utxo_ret.lock().unwrap().clone()
+ }
+}
+
+impl chain::Filter for TestChainSource {
+ fn register_tx(&self, txid: &Txid, script_pubkey: &Script) {
+ self.watched_txn.lock().unwrap().insert((*txid, script_pubkey.clone()));
+ }
+
+ fn register_output(&self, output: WatchedOutput) -> Option<(usize, Transaction)> {
+ let dependent_tx = match &mut *self.expectations.lock().unwrap() {
+ None => None,
+ Some(expectations) => match expectations.pop_front() {
+ None => {
+ panic!("Unexpected register_output: {:?}",
+ (output.outpoint, output.script_pubkey));
+ },
+ Some(expectation) => {
+ assert_eq!(output.outpoint, expectation.outpoint());
+ assert_eq!(&output.script_pubkey, expectation.script_pubkey());
+ expectation.returns
+ },
+ },
+ };
+
+ self.watched_outputs.lock().unwrap().insert((output.outpoint, output.script_pubkey));
+ dependent_tx
+ }
+}
+
+impl Drop for TestChainSource {
+ fn drop(&mut self) {
+ if std::thread::panicking() {
+ return;
+ }
+
+ if let Some(expectations) = &*self.expectations.lock().unwrap() {
+ if !expectations.is_empty() {
+ panic!("Unsatisfied expectations: {:?}", expectations);
+ }
+ }
+ }
+}
+
+/// An expectation that [`chain::Filter::register_output`] was called with a transaction output and
+/// returns an optional dependent transaction that spends the output in the same block.
+pub struct OnRegisterOutput {
+ /// The transaction output to register.
+ pub with: TxOutReference,
+
+ /// A dependent transaction spending the output along with its position in the block.
+ pub returns: Option<(usize, Transaction)>,
+}
+
+/// A transaction output as identified by an index into a transaction's output list.
+pub struct TxOutReference(pub Transaction, pub usize);
+
+impl OnRegisterOutput {
+ fn outpoint(&self) -> OutPoint {
+ let txid = self.with.0.txid();
+ let index = self.with.1 as u16;
+ OutPoint { txid, index }
+ }
+
+ fn script_pubkey(&self) -> &Script {
+ let index = self.with.1;
+ &self.with.0.output[index].script_pubkey
+ }
+}
+
+impl std::fmt::Debug for OnRegisterOutput {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("OnRegisterOutput")
+ .field("outpoint", &self.outpoint())
+ .field("script_pubkey", self.script_pubkey())
+ .finish()
+ }