@@ -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 crossbeam_channel:: Receiver ;
88use rayon:: prelude:: * ;
@@ -19,7 +19,7 @@ use crate::{
1919 merkle:: Proof ,
2020 metrics:: { self , Histogram , Metrics } ,
2121 signals:: Signal ,
22- status:: ScriptHashStatus ,
22+ status:: { OutPointStatus , ScriptHashStatus } ,
2323 tracker:: Tracker ,
2424 types:: ScriptHash ,
2525} ;
@@ -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 ) ]
@@ -176,7 +177,25 @@ impl Rpc {
176177 }
177178 } )
178179 . collect :: < Result < Vec < Value > > > ( )
179- . context ( "failed to update status" ) ?;
180+ . context ( "failed to update scripthash status" ) ?;
181+
182+ notifications. extend (
183+ client
184+ . outpoints
185+ . par_iter_mut ( )
186+ . filter_map ( |( outpoint, status) | -> Option < Result < Value > > {
187+ match self . tracker . update_outpoint_status ( status, & self . daemon ) {
188+ Ok ( true ) => Some ( Ok ( notification (
189+ "blockchain.outpoint.subscribe" ,
190+ & [ json ! ( [ outpoint. txid, outpoint. vout] ) , json ! ( status) ] ,
191+ ) ) ) ,
192+ Ok ( false ) => None , // outpoint status is the same
193+ Err ( e) => Some ( Err ( e) ) ,
194+ }
195+ } )
196+ . collect :: < Result < Vec < Value > > > ( )
197+ . context ( "failed to update scripthash status" ) ?,
198+ ) ;
180199
181200 if let Some ( old_tip) = client. tip {
182201 let new_tip = self . tracker . chain ( ) . tip ( ) ;
@@ -332,6 +351,28 @@ impl Rpc {
332351 } )
333352 }
334353
354+ fn outpoint_subscribe ( & self , client : & mut Client , ( txid, vout) : ( Txid , u32 ) ) -> Result < Value > {
355+ let outpoint = OutPoint :: new ( txid, vout) ;
356+ Ok ( match client. outpoints . entry ( outpoint) {
357+ Entry :: Occupied ( e) => json ! ( e. get( ) ) ,
358+ Entry :: Vacant ( e) => {
359+ let outpoint = OutPoint :: new ( txid, vout) ;
360+ let mut status = OutPointStatus :: new ( outpoint) ;
361+ self . tracker
362+ . update_outpoint_status ( & mut status, & self . daemon ) ?;
363+ json ! ( e. insert( status) )
364+ }
365+ } )
366+ }
367+
368+ fn outpoint_unsubscribe (
369+ & self ,
370+ client : & mut Client ,
371+ ( txid, vout) : ( Txid , u32 ) ,
372+ ) -> Result < Value > {
373+ Ok ( json ! ( client. outpoints. remove( & OutPoint :: new( txid, vout) ) ) )
374+ }
375+
335376 fn new_status ( & self , scripthash : ScriptHash ) -> Result < ScriptHashStatus > {
336377 let mut status = ScriptHashStatus :: new ( scripthash) ;
337378 self . tracker
@@ -505,6 +546,8 @@ impl Rpc {
505546 Params :: Features => self . features ( ) ,
506547 Params :: HeadersSubscribe => self . headers_subscribe ( client) ,
507548 Params :: MempoolFeeHistogram => self . get_fee_histogram ( ) ,
549+ Params :: OutPointSubscribe ( args) => self . outpoint_subscribe ( client, * args) ,
550+ Params :: OutPointUnsubscribe ( args) => self . outpoint_unsubscribe ( client, * args) ,
508551 Params :: PeersSubscribe => Ok ( json ! ( [ ] ) ) ,
509552 Params :: Ping => Ok ( Value :: Null ) ,
510553 Params :: RelayFee => self . relayfee ( ) ,
@@ -527,19 +570,21 @@ enum Params {
527570 Banner ,
528571 BlockHeader ( ( usize , ) ) ,
529572 BlockHeaders ( ( usize , usize ) ) ,
530- TransactionBroadcast ( ( String , ) ) ,
531573 Donation ,
532574 EstimateFee ( ( u16 , ) ) ,
533575 Features ,
534576 HeadersSubscribe ,
535577 MempoolFeeHistogram ,
578+ OutPointSubscribe ( ( Txid , u32 ) ) , // TODO: support spk_hint
579+ OutPointUnsubscribe ( ( Txid , u32 ) ) ,
536580 PeersSubscribe ,
537581 Ping ,
538582 RelayFee ,
539583 ScriptHashGetBalance ( ( ScriptHash , ) ) ,
540584 ScriptHashGetHistory ( ( ScriptHash , ) ) ,
541585 ScriptHashListUnspent ( ( ScriptHash , ) ) ,
542586 ScriptHashSubscribe ( ( ScriptHash , ) ) ,
587+ TransactionBroadcast ( ( String , ) ) ,
543588 TransactionGet ( TxGetArgs ) ,
544589 TransactionGetMerkle ( ( Txid , usize ) ) ,
545590 Version ( ( String , Version ) ) ,
@@ -552,6 +597,8 @@ impl Params {
552597 "blockchain.block.headers" => Params :: BlockHeaders ( convert ( params) ?) ,
553598 "blockchain.estimatefee" => Params :: EstimateFee ( convert ( params) ?) ,
554599 "blockchain.headers.subscribe" => Params :: HeadersSubscribe ,
600+ "blockchain.outpoint.subscribe" => Params :: OutPointSubscribe ( convert ( params) ?) ,
601+ "blockchain.outpoint.unsubscribe" => Params :: OutPointUnsubscribe ( convert ( params) ?) ,
555602 "blockchain.relayfee" => Params :: RelayFee ,
556603 "blockchain.scripthash.get_balance" => Params :: ScriptHashGetBalance ( convert ( params) ?) ,
557604 "blockchain.scripthash.get_history" => Params :: ScriptHashGetHistory ( convert ( params) ?) ,
0 commit comments