@@ -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 } ,
2121 signals:: Signal ,
22- status:: ScriptHashStatus ,
22+ status:: { OutPointStatus , ScriptHashStatus } ,
2323 tracker:: Tracker ,
2424 types:: ScriptHash ,
2525} ;
@@ -34,6 +34,7 @@ const UNKNOWN_FEE: isize = -1; // (allowed by Electrum protocol)
3434pub struct Client {
3535 tip : Option < BlockHash > ,
3636 scripthashes : HashMap < ScriptHash , ScriptHashStatus > ,
37+ outpoints : HashMap < OutPoint , OutPointStatus > ,
3738}
3839
3940#[ derive( Deserialize ) ]
@@ -178,7 +179,25 @@ impl Rpc {
178179 }
179180 } )
180181 . collect :: < Result < Vec < Value > > > ( )
181- . context ( "failed to update status" ) ?;
182+ . context ( "failed to update scripthash status" ) ?;
183+
184+ notifications. extend (
185+ client
186+ . outpoints
187+ . par_iter_mut ( )
188+ . filter_map ( |( outpoint, status) | -> Option < Result < Value > > {
189+ match self . tracker . update_outpoint_status ( status, & self . daemon ) {
190+ Ok ( true ) => Some ( Ok ( notification (
191+ "blockchain.outpoint.subscribe" ,
192+ & [ json ! ( [ outpoint. txid, outpoint. vout] ) , json ! ( status) ] ,
193+ ) ) ) ,
194+ Ok ( false ) => None , // outpoint status is the same
195+ Err ( e) => Some ( Err ( e) ) ,
196+ }
197+ } )
198+ . collect :: < Result < Vec < Value > > > ( )
199+ . context ( "failed to update scripthash status" ) ?,
200+ ) ;
182201
183202 if let Some ( old_tip) = client. tip {
184203 let new_tip = self . tracker . chain ( ) . tip ( ) ;
@@ -306,6 +325,28 @@ impl Rpc {
306325 Ok ( json ! ( result) )
307326 }
308327
328+ fn outpoint_subscribe ( & self , client : & mut Client , ( txid, vout) : ( Txid , u32 ) ) -> Result < Value > {
329+ let outpoint = OutPoint :: new ( txid, vout) ;
330+ Ok ( match client. outpoints . entry ( outpoint) {
331+ Entry :: Occupied ( e) => json ! ( e. get( ) ) ,
332+ Entry :: Vacant ( e) => {
333+ let outpoint = OutPoint :: new ( txid, vout) ;
334+ let mut status = OutPointStatus :: new ( outpoint) ;
335+ self . tracker
336+ . update_outpoint_status ( & mut status, & self . daemon ) ?;
337+ json ! ( e. insert( status) )
338+ }
339+ } )
340+ }
341+
342+ fn outpoint_unsubscribe (
343+ & self ,
344+ client : & mut Client ,
345+ ( txid, vout) : ( Txid , u32 ) ,
346+ ) -> Result < Value > {
347+ Ok ( json ! ( client. outpoints. remove( & OutPoint :: new( txid, vout) ) ) )
348+ }
349+
309350 fn new_status ( & self , scripthash : ScriptHash ) -> Result < ScriptHashStatus > {
310351 let mut status = ScriptHashStatus :: new ( scripthash) ;
311352 self . tracker
@@ -440,6 +481,8 @@ impl Rpc {
440481 Call :: HeadersSubscribe => self . headers_subscribe ( client) ,
441482 Call :: MempoolFeeHistogram => self . get_fee_histogram ( ) ,
442483 Call :: PeersSubscribe => Ok ( json ! ( [ ] ) ) ,
484+ Call :: OutPointSubscribe ( args) => self . outpoint_subscribe ( client, args) ,
485+ Call :: OutPointUnsubscribe ( args) => self . outpoint_unsubscribe ( client, args) ,
443486 Call :: Ping => Ok ( Value :: Null ) ,
444487 Call :: RelayFee => self . relayfee ( ) ,
445488 Call :: ScriptHashGetBalance ( args) => self . scripthash_get_balance ( client, args) ,
@@ -473,19 +516,21 @@ enum Call {
473516 Banner ,
474517 BlockHeader ( ( usize , ) ) ,
475518 BlockHeaders ( ( usize , usize ) ) ,
476- TransactionBroadcast ( ( String , ) ) ,
477519 Donation ,
478520 EstimateFee ( ( u16 , ) ) ,
479521 Features ,
480522 HeadersSubscribe ,
481523 MempoolFeeHistogram ,
524+ OutPointSubscribe ( ( Txid , u32 ) ) , // TODO: support spk_hint
525+ OutPointUnsubscribe ( ( Txid , u32 ) ) ,
482526 PeersSubscribe ,
483527 Ping ,
484528 RelayFee ,
485529 ScriptHashGetBalance ( ( ScriptHash , ) ) ,
486530 ScriptHashGetHistory ( ( ScriptHash , ) ) ,
487531 ScriptHashListUnspent ( ( ScriptHash , ) ) ,
488532 ScriptHashSubscribe ( ( ScriptHash , ) ) ,
533+ TransactionBroadcast ( ( String , ) ) ,
489534 TransactionGet ( TxGetArgs ) ,
490535 TransactionGetMerkle ( ( Txid , usize ) ) ,
491536 Version ( ( String , Version ) ) ,
@@ -503,6 +548,8 @@ impl Call {
503548 "blockchain.scripthash.get_history" => Call :: ScriptHashGetHistory ( convert ( params) ?) ,
504549 "blockchain.scripthash.listunspent" => Call :: ScriptHashListUnspent ( convert ( params) ?) ,
505550 "blockchain.scripthash.subscribe" => Call :: ScriptHashSubscribe ( convert ( params) ?) ,
551+ "blockchain.outpoint.subscribe" => Call :: OutPointSubscribe ( convert ( params) ?) ,
552+ "blockchain.outpoint.unsubscribe" => Call :: OutPointUnsubscribe ( convert ( params) ?) ,
506553 "blockchain.transaction.broadcast" => Call :: TransactionBroadcast ( convert ( params) ?) ,
507554 "blockchain.transaction.get" => Call :: TransactionGet ( convert ( params) ?) ,
508555 "blockchain.transaction.get_merkle" => Call :: TransactionGetMerkle ( convert ( params) ?) ,
0 commit comments