@@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
22use bitcoin:: {
33 consensus:: { deserialize, serialize} ,
44 hashes:: hex:: { FromHex , ToHex } ,
5- BlockHash , Txid ,
5+ BlockHash , OutPoint , Txid ,
66} ;
77use rayon:: prelude:: * ;
88use serde_derive:: Deserialize ;
@@ -17,7 +17,7 @@ use crate::{
1717 daemon:: { self , extract_bitcoind_error, Daemon } ,
1818 merkle:: Proof ,
1919 metrics:: Histogram ,
20- status:: ScriptHashStatus ,
20+ status:: { OutPointStatus , ScriptHashStatus } ,
2121 tracker:: Tracker ,
2222 types:: ScriptHash ,
2323} ;
@@ -32,6 +32,7 @@ const UNKNOWN_FEE: isize = -1; // (allowed by Electrum protocol)
3232pub struct Client {
3333 tip : Option < BlockHash > ,
3434 scripthashes : HashMap < ScriptHash , ScriptHashStatus > ,
35+ outpoints : HashMap < OutPoint , OutPointStatus > ,
3536}
3637
3738#[ derive( Deserialize ) ]
@@ -158,7 +159,25 @@ impl Rpc {
158159 }
159160 } )
160161 . collect :: < Result < Vec < Value > > > ( )
161- . context ( "failed to update status" ) ?;
162+ . context ( "failed to update scripthash status" ) ?;
163+
164+ notifications. extend (
165+ client
166+ . outpoints
167+ . par_iter_mut ( )
168+ . filter_map ( |( outpoint, status) | -> Option < Result < Value > > {
169+ match self . tracker . update_outpoint_status ( status, & self . daemon ) {
170+ Ok ( true ) => Some ( Ok ( notification (
171+ "blockchain.outpoint.subscribe" ,
172+ & [ json ! ( [ outpoint. txid, outpoint. vout] ) , json ! ( status) ] ,
173+ ) ) ) ,
174+ Ok ( false ) => None , // outpoint status is the same
175+ Err ( e) => Some ( Err ( e) ) ,
176+ }
177+ } )
178+ . collect :: < Result < Vec < Value > > > ( )
179+ . context ( "failed to update scripthash status" ) ?,
180+ ) ;
162181
163182 if let Some ( old_tip) = client. tip {
164183 let new_tip = self . tracker . chain ( ) . tip ( ) ;
@@ -286,6 +305,28 @@ impl Rpc {
286305 Ok ( json ! ( result) )
287306 }
288307
308+ fn outpoint_subscribe ( & self , client : & mut Client , ( txid, vout) : ( Txid , u32 ) ) -> Result < Value > {
309+ let outpoint = OutPoint :: new ( txid, vout) ;
310+ Ok ( match client. outpoints . entry ( outpoint) {
311+ Entry :: Occupied ( e) => json ! ( e. get( ) ) ,
312+ Entry :: Vacant ( e) => {
313+ let outpoint = OutPoint :: new ( txid, vout) ;
314+ let mut status = OutPointStatus :: new ( outpoint) ;
315+ self . tracker
316+ . update_outpoint_status ( & mut status, & self . daemon ) ?;
317+ json ! ( e. insert( status) )
318+ }
319+ } )
320+ }
321+
322+ fn outpoint_unsubscribe (
323+ & self ,
324+ client : & mut Client ,
325+ ( txid, vout) : ( Txid , u32 ) ,
326+ ) -> Result < Value > {
327+ Ok ( json ! ( client. outpoints. remove( & OutPoint :: new( txid, vout) ) ) )
328+ }
329+
289330 fn new_status ( & self , scripthash : ScriptHash ) -> Result < ScriptHashStatus > {
290331 let mut status = ScriptHashStatus :: new ( scripthash) ;
291332 self . tracker
@@ -420,6 +461,8 @@ impl Rpc {
420461 Call :: HeadersSubscribe => self . headers_subscribe ( client) ,
421462 Call :: MempoolFeeHistogram => self . get_fee_histogram ( ) ,
422463 Call :: PeersSubscribe => Ok ( json ! ( [ ] ) ) ,
464+ Call :: OutPointSubscribe ( args) => self . outpoint_subscribe ( client, args) ,
465+ Call :: OutPointUnsubscribe ( args) => self . outpoint_unsubscribe ( client, args) ,
423466 Call :: Ping => Ok ( Value :: Null ) ,
424467 Call :: RelayFee => self . relayfee ( ) ,
425468 Call :: ScriptHashGetBalance ( args) => self . scripthash_get_balance ( client, args) ,
@@ -453,19 +496,21 @@ enum Call {
453496 Banner ,
454497 BlockHeader ( ( usize , ) ) ,
455498 BlockHeaders ( ( usize , usize ) ) ,
456- TransactionBroadcast ( ( String , ) ) ,
457499 Donation ,
458500 EstimateFee ( ( u16 , ) ) ,
459501 Features ,
460502 HeadersSubscribe ,
461503 MempoolFeeHistogram ,
504+ OutPointSubscribe ( ( Txid , u32 ) ) , // TODO: support spk_hint
505+ OutPointUnsubscribe ( ( Txid , u32 ) ) ,
462506 PeersSubscribe ,
463507 Ping ,
464508 RelayFee ,
465509 ScriptHashGetBalance ( ( ScriptHash , ) ) ,
466510 ScriptHashGetHistory ( ( ScriptHash , ) ) ,
467511 ScriptHashListUnspent ( ( ScriptHash , ) ) ,
468512 ScriptHashSubscribe ( ( ScriptHash , ) ) ,
513+ TransactionBroadcast ( ( String , ) ) ,
469514 TransactionGet ( TxGetArgs ) ,
470515 TransactionGetMerkle ( ( Txid , usize ) ) ,
471516 Version ( ( String , Version ) ) ,
@@ -483,6 +528,8 @@ impl Call {
483528 "blockchain.scripthash.get_history" => Call :: ScriptHashGetHistory ( convert ( params) ?) ,
484529 "blockchain.scripthash.listunspent" => Call :: ScriptHashListUnspent ( convert ( params) ?) ,
485530 "blockchain.scripthash.subscribe" => Call :: ScriptHashSubscribe ( convert ( params) ?) ,
531+ "blockchain.outpoint.subscribe" => Call :: OutPointSubscribe ( convert ( params) ?) ,
532+ "blockchain.outpoint.unsubscribe" => Call :: OutPointUnsubscribe ( convert ( params) ?) ,
486533 "blockchain.transaction.broadcast" => Call :: TransactionBroadcast ( convert ( params) ?) ,
487534 "blockchain.transaction.get" => Call :: TransactionGet ( convert ( params) ?) ,
488535 "blockchain.transaction.get_merkle" => Call :: TransactionGetMerkle ( convert ( params) ?) ,
0 commit comments