@@ -10,6 +10,7 @@ import (
1010 "net"
1111 "net/http"
1212 "sync"
13+ "sync/atomic"
1314 "time"
1415
1516 "github.com/btcsuite/btcd/btcutil"
@@ -725,8 +726,8 @@ var _ WebAPIFeeSource = (*SparseConfFeeSource)(nil)
725726// WebAPIEstimator is an implementation of the Estimator interface that
726727// queries an HTTP-based fee estimation from an existing web API.
727728type WebAPIEstimator struct {
728- started sync. Once
729- stopped sync. Once
729+ started atomic. Bool
730+ stopped atomic. Bool
730731
731732 // apiSource is the backing web API source we'll use for our queries.
732733 apiSource WebAPIFeeSource
@@ -792,6 +793,12 @@ func NewWebAPIEstimator(api WebAPIFeeSource, noCache bool,
792793func (w * WebAPIEstimator ) EstimateFeePerKW (numBlocks uint32 ) (
793794 SatPerKWeight , error ) {
794795
796+ // If the estimator hasn't been started yet, we'll return an error as
797+ // we can't provide a fee estimate.
798+ if ! w .started .Load () {
799+ return 0 , fmt .Errorf ("estimator not started" )
800+ }
801+
795802 if numBlocks > MaxBlockTarget {
796803 numBlocks = MaxBlockTarget
797804 } else if numBlocks < minBlockTarget {
@@ -831,49 +838,56 @@ func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) (
831838//
832839// NOTE: This method is part of the Estimator interface.
833840func (w * WebAPIEstimator ) Start () error {
841+ log .Infof ("Starting Web API fee estimator..." )
842+
843+ // Return an error if it's already been started.
844+ if w .started .Load () {
845+ return fmt .Errorf ("web API fee estimator already started" )
846+ }
847+ defer w .started .Store (true )
848+
849+ // During startup we'll query the API to initialize the fee map.
850+ w .updateFeeEstimates ()
851+
834852 // No update loop is needed when we don't cache.
835853 if w .noCache {
836854 return nil
837855 }
838856
839- var err error
840- w .started .Do (func () {
841- log .Infof ("Starting web API fee estimator" )
857+ feeUpdateTimeout := w .randomFeeUpdateTimeout ()
842858
843- feeUpdateTimeout := w .randomFeeUpdateTimeout ()
859+ log .Infof ("Web API fee estimator using update timeout of %v" ,
860+ feeUpdateTimeout )
844861
845- log .Infof ("Web API fee estimator using update timeout of %v" ,
846- feeUpdateTimeout )
847-
848- w .updateFeeTicker = time .NewTicker (feeUpdateTimeout )
849- w .updateFeeEstimates ()
862+ w .updateFeeTicker = time .NewTicker (feeUpdateTimeout )
850863
851- w .wg .Add (1 )
852- go w .feeUpdateManager ()
864+ w .wg .Add (1 )
865+ go w .feeUpdateManager ()
853866
854- })
855-
856- return err
867+ return nil
857868}
858869
859870// Stop stops any spawned goroutines and cleans up the resources used by the
860871// fee estimator.
861872//
862873// NOTE: This method is part of the Estimator interface.
863874func (w * WebAPIEstimator ) Stop () error {
875+ log .Infof ("Stopping web API fee estimator" )
876+
877+ if w .stopped .Swap (true ) {
878+ return fmt .Errorf ("web API fee estimator already stopped" )
879+ }
880+
864881 // Update loop is not running when we don't cache.
865882 if w .noCache {
866883 return nil
867884 }
868885
869- w .stopped .Do (func () {
870- log .Infof ("Stopping web API fee estimator" )
886+ w .updateFeeTicker .Stop ()
871887
872- w .updateFeeTicker .Stop ()
888+ close (w .quit )
889+ w .wg .Wait ()
873890
874- close (w .quit )
875- w .wg .Wait ()
876- })
877891 return nil
878892}
879893
@@ -882,6 +896,10 @@ func (w *WebAPIEstimator) Stop() error {
882896//
883897// NOTE: This method is part of the Estimator interface.
884898func (w * WebAPIEstimator ) RelayFeePerKW () SatPerKWeight {
899+ if ! w .started .Load () {
900+ log .Error ("WebAPIEstimator not started" )
901+ }
902+
885903 // Get fee estimates now if we don't refresh periodically.
886904 if w .noCache {
887905 w .updateFeeEstimates ()
0 commit comments