@@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
22use bitcoin:: {
33 consensus:: { deserialize, encode:: serialize_hex} ,
44 hashes:: hex:: FromHex ,
5- BlockHash , Txid ,
5+ BlockHash , OutPoint , Txid ,
66} ;
77use crossbeam_channel:: Receiver ;
88use rayon:: prelude:: * ;
@@ -21,7 +21,7 @@ use crate::{
2121 merkle:: Proof ,
2222 metrics:: { self , Histogram , Metrics } ,
2323 signals:: Signal ,
24- status:: ScriptHashStatus ,
24+ status:: { OutPointStatus , ScriptHashStatus } ,
2525 tracker:: Tracker ,
2626 types:: ScriptHash ,
2727} ;
@@ -36,6 +36,7 @@ const UNSUBSCRIBED_QUERY_MESSAGE: &str = "your wallet uses less efficient method
3636pub struct Client {
3737 tip : Option < BlockHash > ,
3838 scripthashes : HashMap < ScriptHash , ScriptHashStatus > ,
39+ outpoints : HashMap < OutPoint , OutPointStatus > ,
3940}
4041
4142#[ derive( Deserialize ) ]
@@ -185,7 +186,25 @@ impl Rpc {
185186 }
186187 } )
187188 . collect :: < Result < Vec < Value > > > ( )
188- . context ( "failed to update status" ) ?;
189+ . context ( "failed to update scripthash status" ) ?;
190+
191+ notifications. extend (
192+ client
193+ . outpoints
194+ . par_iter_mut ( )
195+ . filter_map ( |( outpoint, status) | -> Option < Result < Value > > {
196+ match self . tracker . update_outpoint_status ( status, & self . daemon ) {
197+ Ok ( true ) => Some ( Ok ( notification (
198+ "blockchain.outpoint.subscribe" ,
199+ & [ json ! ( [ outpoint. txid, outpoint. vout] ) , json ! ( status) ] ,
200+ ) ) ) ,
201+ Ok ( false ) => None , // outpoint status is the same
202+ Err ( e) => Some ( Err ( e) ) ,
203+ }
204+ } )
205+ . collect :: < Result < Vec < Value > > > ( )
206+ . context ( "failed to update scripthash status" ) ?,
207+ ) ;
189208
190209 if let Some ( old_tip) = client. tip {
191210 let new_tip = self . tracker . chain ( ) . tip ( ) ;
@@ -350,6 +369,28 @@ impl Rpc {
350369 } )
351370 }
352371
372+ fn outpoint_subscribe ( & self , client : & mut Client , ( txid, vout) : ( Txid , u32 ) ) -> Result < Value > {
373+ let outpoint = OutPoint :: new ( txid, vout) ;
374+ Ok ( match client. outpoints . entry ( outpoint) {
375+ Entry :: Occupied ( e) => json ! ( e. get( ) ) ,
376+ Entry :: Vacant ( e) => {
377+ let outpoint = OutPoint :: new ( txid, vout) ;
378+ let mut status = OutPointStatus :: new ( outpoint) ;
379+ self . tracker
380+ . update_outpoint_status ( & mut status, & self . daemon ) ?;
381+ json ! ( e. insert( status) )
382+ }
383+ } )
384+ }
385+
386+ fn outpoint_unsubscribe (
387+ & self ,
388+ client : & mut Client ,
389+ ( txid, vout) : ( Txid , u32 ) ,
390+ ) -> Result < Value > {
391+ Ok ( json ! ( client. outpoints. remove( & OutPoint :: new( txid, vout) ) ) )
392+ }
393+
353394 fn new_status ( & self , scripthash : ScriptHash ) -> Result < ScriptHashStatus > {
354395 let mut status = ScriptHashStatus :: new ( scripthash) ;
355396 self . tracker
@@ -548,6 +589,8 @@ impl Rpc {
548589 Params :: Features => self . features ( ) ,
549590 Params :: HeadersSubscribe => self . headers_subscribe ( client) ,
550591 Params :: MempoolFeeHistogram => self . get_fee_histogram ( ) ,
592+ Params :: OutPointSubscribe ( args) => self . outpoint_subscribe ( client, * args) ,
593+ Params :: OutPointUnsubscribe ( args) => self . outpoint_unsubscribe ( client, * args) ,
551594 Params :: PeersSubscribe => Ok ( json ! ( [ ] ) ) ,
552595 Params :: Ping => Ok ( Value :: Null ) ,
553596 Params :: RelayFee => self . relayfee ( ) ,
@@ -572,12 +615,13 @@ enum Params {
572615 Banner ,
573616 BlockHeader ( ( usize , ) ) ,
574617 BlockHeaders ( ( usize , usize ) ) ,
575- TransactionBroadcast ( ( String , ) ) ,
576618 Donation ,
577619 EstimateFee ( ( u16 , ) ) ,
578620 Features ,
579621 HeadersSubscribe ,
580622 MempoolFeeHistogram ,
623+ OutPointSubscribe ( ( Txid , u32 ) ) , // TODO: support spk_hint
624+ OutPointUnsubscribe ( ( Txid , u32 ) ) ,
581625 PeersSubscribe ,
582626 Ping ,
583627 RelayFee ,
@@ -586,6 +630,7 @@ enum Params {
586630 ScriptHashListUnspent ( ( ScriptHash , ) ) ,
587631 ScriptHashSubscribe ( ( ScriptHash , ) ) ,
588632 ScriptHashUnsubscribe ( ( ScriptHash , ) ) ,
633+ TransactionBroadcast ( ( String , ) ) ,
589634 TransactionGet ( TxGetArgs ) ,
590635 TransactionGetMerkle ( ( Txid , usize ) ) ,
591636 TransactionFromPosition ( ( usize , usize , bool ) ) ,
@@ -599,6 +644,8 @@ impl Params {
599644 "blockchain.block.headers" => Params :: BlockHeaders ( convert ( params) ?) ,
600645 "blockchain.estimatefee" => Params :: EstimateFee ( convert ( params) ?) ,
601646 "blockchain.headers.subscribe" => Params :: HeadersSubscribe ,
647+ "blockchain.outpoint.subscribe" => Params :: OutPointSubscribe ( convert ( params) ?) ,
648+ "blockchain.outpoint.unsubscribe" => Params :: OutPointUnsubscribe ( convert ( params) ?) ,
602649 "blockchain.relayfee" => Params :: RelayFee ,
603650 "blockchain.scripthash.get_balance" => Params :: ScriptHashGetBalance ( convert ( params) ?) ,
604651 "blockchain.scripthash.get_history" => Params :: ScriptHashGetHistory ( convert ( params) ?) ,
0 commit comments