diff --git a/chain/cached_fee_estimator.go b/chain/cached_fee_estimator.go new file mode 100644 index 0000000..4f249c6 --- /dev/null +++ b/chain/cached_fee_estimator.go @@ -0,0 +1,61 @@ +package chain + +import ( + "context" + "sync" + "time" +) + +var cacheDuration time.Duration = time.Minute * 5 + +type feeCache struct { + time time.Time + estimation *FeeEstimation +} + +type CachedFeeEstimator struct { + cache map[FeeStrategy]*feeCache + inner FeeEstimator + mtx sync.Mutex +} + +func NewCachedFeeEstimator(inner FeeEstimator) *CachedFeeEstimator { + return &CachedFeeEstimator{ + inner: inner, + cache: make(map[FeeStrategy]*feeCache), + } +} + +func (e *CachedFeeEstimator) EstimateFeeRate( + ctx context.Context, + strategy FeeStrategy, +) (*FeeEstimation, error) { + + // Make sure we're in a lock, because we're reading/writing a map. + e.mtx.Lock() + defer e.mtx.Unlock() + + // See if there's a cached value first. + cached, ok := e.cache[strategy] + + // If there is and it's still valid, return that. + if ok && cached.time.Add(cacheDuration).After(time.Now()) { + return cached.estimation, nil + } + + // There was no valid cache. + // Fetch the new fee estimate. + now := time.Now() + estimation, err := e.inner.EstimateFeeRate(ctx, strategy) + if err != nil { + return nil, err + } + + // Cache it. + e.cache[strategy] = &feeCache{ + time: now, + estimation: estimation, + } + + return estimation, nil +}