github.com/decred/dcrlnd@v0.7.6/lnwallet/chainfee/minfeemanager.go (about) 1 package chainfee 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 const defaultUpdateInterval = 10 * time.Minute 9 10 // minFeeManager is used to store and update the minimum fee that is required 11 // by a transaction to be accepted to the mempool. The minFeeManager ensures 12 // that the backend used to fetch the fee is not queried too regularly. 13 type minFeeManager struct { 14 mu sync.Mutex 15 minFeePerKW AtomPerKByte 16 lastUpdatedTime time.Time 17 minUpdateInterval time.Duration 18 fetchFeeFunc fetchFee 19 } 20 21 // fetchFee represents a function that can be used to fetch a fee. 22 type fetchFee func() (AtomPerKByte, error) 23 24 // newMinFeeManager creates a new minFeeManager and uses the 25 // given fetchMinFee function to set the minFeePerKW of the minFeeManager. 26 // This function requires the fetchMinFee function to succeed. 27 func newMinFeeManager(minUpdateInterval time.Duration, 28 fetchMinFee fetchFee) (*minFeeManager, error) { 29 30 minFee, err := fetchMinFee() 31 if err != nil { 32 return nil, err 33 } 34 35 // Ensure that the minimum fee we use is always clamped by our fee 36 // floor. 37 if minFee < FeePerKBFloor { 38 minFee = FeePerKBFloor 39 } 40 41 return &minFeeManager{ 42 minFeePerKW: minFee, 43 lastUpdatedTime: time.Now(), 44 minUpdateInterval: minUpdateInterval, 45 fetchFeeFunc: fetchMinFee, 46 }, nil 47 } 48 49 // fetchMinFee returns the stored minFeePerKW if it has been updated recently 50 // or if the call to the chain backend fails. Otherwise, it sets the stored 51 // minFeePerKW to the fee returned from the backend and floors it based on 52 // our fee floor. 53 func (m *minFeeManager) fetchMinFee() AtomPerKByte { 54 m.mu.Lock() 55 defer m.mu.Unlock() 56 57 if time.Since(m.lastUpdatedTime) < m.minUpdateInterval { 58 return m.minFeePerKW 59 } 60 61 newMinFee, err := m.fetchFeeFunc() 62 if err != nil { 63 log.Errorf("Unable to fetch updated min fee from chain "+ 64 "backend. Using last known min fee instead: %v", err) 65 66 return m.minFeePerKW 67 } 68 69 // By default, we'll use the backend node's minimum fee as the 70 // minimum fee rate we'll propose for transactions. However, if this 71 // happens to be lower than our fee floor, we'll enforce that instead. 72 m.minFeePerKW = newMinFee 73 if m.minFeePerKW < FeePerKBFloor { 74 m.minFeePerKW = FeePerKBFloor 75 } 76 m.lastUpdatedTime = time.Now() 77 78 log.Debugf("Using minimum fee rate of %v sat/kw", 79 int64(m.minFeePerKW)) 80 81 return m.minFeePerKW 82 }