@@ -628,9 +628,10 @@ var _ Estimator = (*BitcoindEstimator)(nil)
628628// implementation of this interface in order to allow the WebAPIEstimator to
629629// be fully generic in its logic.
630630type WebAPIFeeSource interface {
631- // GetFeeMap will query the web API, parse the response and return a
632- // map of confirmation targets to sat/kw fees.
633- GetFeeMap () (map [uint32 ]uint32 , error )
631+ // GetFeeInfo will query the web API, parse the response into a
632+ // WebAPIResponse which contains a map of confirmation targets to
633+ // sat/kw fees and min relay feerate.
634+ GetFeeInfo () (WebAPIResponse , error )
634635}
635636
636637// SparseConfFeeSource is an implementation of the WebAPIFeeSource that utilizes
@@ -642,30 +643,43 @@ type SparseConfFeeSource struct {
642643 URL string
643644}
644645
646+ // WebAPIResponse is the response returned by the fee estimation API.
647+ type WebAPIResponse struct {
648+ // FeeByBlockTarget is a map of confirmation targets to sat/kvb fees.
649+ FeeByBlockTarget map [uint32 ]uint32 `json:"fee_by_block_target"`
650+
651+ // MinRelayFeerate is the minimum relay fee in sat/kvb.
652+ MinRelayFeerate SatPerKVByte `json:"min_relay_feerate"`
653+ }
654+
645655// parseResponse attempts to parse the body of the response generated by the
646656// above query URL. Typically this will be JSON, but the specifics are left to
647657// the WebAPIFeeSource implementation.
648658func (s SparseConfFeeSource ) parseResponse (r io.Reader ) (
649- map [uint32 ]uint32 , error ) {
650-
651- type jsonResp struct {
652- FeeByBlockTarget map [uint32 ]uint32 `json:"fee_by_block_target"`
653- }
659+ WebAPIResponse , error ) {
654660
655- resp := jsonResp {
661+ resp := WebAPIResponse {
656662 FeeByBlockTarget : make (map [uint32 ]uint32 ),
663+ MinRelayFeerate : 0 ,
657664 }
658665 jsonReader := json .NewDecoder (r )
659666 if err := jsonReader .Decode (& resp ); err != nil {
660- return nil , err
667+ return WebAPIResponse {}, err
668+ }
669+
670+ if resp .MinRelayFeerate == 0 {
671+ log .Errorf ("No min relay fee rate available, using default %v" ,
672+ FeePerKwFloor )
673+ resp .MinRelayFeerate = FeePerKwFloor .FeePerKVByte ()
661674 }
662675
663- return resp . FeeByBlockTarget , nil
676+ return resp , nil
664677}
665678
666- // GetFeeMap will query the web API, parse the response and return a map of
667- // confirmation targets to sat/kw fees.
668- func (s SparseConfFeeSource ) GetFeeMap () (map [uint32 ]uint32 , error ) {
679+ // GetFeeInfo will query the web API, parse the response and return a map of
680+ // confirmation targets to sat/kw fees and min relay feerate in a parsed
681+ // response.
682+ func (s SparseConfFeeSource ) GetFeeInfo () (WebAPIResponse , error ) {
669683 // Rather than use the default http.Client, we'll make a custom one
670684 // which will allow us to control how long we'll wait to read the
671685 // response from the service. This way, if the service is down or
@@ -688,20 +702,20 @@ func (s SparseConfFeeSource) GetFeeMap() (map[uint32]uint32, error) {
688702 if err != nil {
689703 log .Errorf ("unable to query web api for fee response: %v" ,
690704 err )
691- return nil , err
705+ return WebAPIResponse {} , err
692706 }
693707 defer resp .Body .Close ()
694708
695709 // Once we've obtained the response, we'll instruct the WebAPIFeeSource
696710 // to parse out the body to obtain our final result.
697- feesByBlockTarget , err := s .parseResponse (resp .Body )
711+ parsedResp , err := s .parseResponse (resp .Body )
698712 if err != nil {
699713 log .Errorf ("unable to parse fee api response: %v" , err )
700714
701- return nil , err
715+ return WebAPIResponse {} , err
702716 }
703717
704- return feesByBlockTarget , nil
718+ return parsedResp , nil
705719}
706720
707721// A compile-time assertion to ensure that SparseConfFeeSource implements the
@@ -726,6 +740,7 @@ type WebAPIEstimator struct {
726740 // rather than re-querying the API, to prevent an inadvertent DoS attack.
727741 feesMtx sync.Mutex
728742 feeByBlockTarget map [uint32 ]uint32
743+ minRelayFeerate SatPerKVByte
729744
730745 // noCache determines whether the web estimator should cache fee
731746 // estimates.
@@ -837,6 +852,7 @@ func (w *WebAPIEstimator) Start() error {
837852 go w .feeUpdateManager ()
838853
839854 })
855+
840856 return err
841857}
842858
@@ -866,7 +882,15 @@ func (w *WebAPIEstimator) Stop() error {
866882//
867883// NOTE: This method is part of the Estimator interface.
868884func (w * WebAPIEstimator ) RelayFeePerKW () SatPerKWeight {
869- return FeePerKwFloor
885+ // Get fee estimates now if we don't refresh periodically.
886+ if w .noCache {
887+ w .updateFeeEstimates ()
888+ }
889+
890+ log .Infof ("Web API returning %v for min relay feerate" ,
891+ w .minRelayFeerate )
892+
893+ return w .minRelayFeerate .FeePerKWeight ()
870894}
871895
872896// randomFeeUpdateTimeout returns a random timeout between minFeeUpdateTimeout
@@ -956,14 +980,21 @@ func (w *WebAPIEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
956980func (w * WebAPIEstimator ) updateFeeEstimates () {
957981 // Once we've obtained the response, we'll instruct the WebAPIFeeSource
958982 // to parse out the body to obtain our final result.
959- feesByBlockTarget , err := w .apiSource .GetFeeMap ()
983+ resp , err := w .apiSource .GetFeeInfo ()
960984 if err != nil {
961985 log .Errorf ("unable to get fee response: %v" , err )
962986 return
963987 }
964988
989+ log .Debugf ("Received response from source: %s" , newLogClosure (
990+ func () string {
991+ resp , _ := json .Marshal (resp )
992+ return string (resp )
993+ }))
994+
965995 w .feesMtx .Lock ()
966- w .feeByBlockTarget = feesByBlockTarget
996+ w .feeByBlockTarget = resp .FeeByBlockTarget
997+ w .minRelayFeerate = resp .MinRelayFeerate
967998 w .feesMtx .Unlock ()
968999}
9691000
0 commit comments