@@ -155,92 +155,91 @@ func TestSparseConfFeeSource(t *testing.T) {
155
155
// as expected.
156
156
func TestWebAPIFeeEstimator (t * testing.T ) {
157
157
t .Parallel ()
158
- feeFloor := uint32 (FeePerKwFloor .FeePerKVByte ())
159
- testFeeRate := feeFloor * 100
158
+
159
+ var (
160
+ minTarget uint32 = 2
161
+ maxTarget uint32 = 6
162
+
163
+ // Fee rates are in sat/kb.
164
+ minFeeRate uint32 = 2000 // 500 sat/kw
165
+ maxFeeRate uint32 = 4000 // 1000 sat/kw
166
+ )
160
167
161
168
testCases := []struct {
162
- name string
163
- target uint32
164
- apiEst uint32
165
- est uint32
166
- err string
169
+ name string
170
+ target uint32
171
+ expectedFeeRate uint32
172
+ expectedErr string
167
173
}{
168
174
{
169
- name : "target_below_min" ,
170
- target : 0 ,
171
- apiEst : 0 ,
172
- est : 0 ,
173
- err : "too low, minimum" ,
174
- },
175
- {
176
- name : "target_w_too-low_fee" ,
177
- target : 100 ,
178
- apiEst : 42 ,
179
- est : feeFloor ,
180
- err : "" ,
175
+ // When requested target is below minBlockTarget, an
176
+ // error is returned.
177
+ name : "target_below_min" ,
178
+ target : 0 ,
179
+ expectedFeeRate : 0 ,
180
+ expectedErr : "too low, minimum" ,
181
181
},
182
182
{
183
- name : "API-omitted_target" ,
184
- target : 2 ,
185
- apiEst : 0 ,
186
- est : testFeeRate ,
187
- err : "" ,
183
+ // When requested target is larger than the max cached
184
+ // target, the fee rate of the max cached target is
185
+ // returned.
186
+ name : "target_w_too-low_fee" ,
187
+ target : maxTarget + 100 ,
188
+ expectedFeeRate : minFeeRate ,
189
+ expectedErr : "" ,
188
190
},
189
191
{
190
- name : "valid_target" ,
191
- target : 20 ,
192
- apiEst : testFeeRate ,
193
- est : testFeeRate ,
194
- err : "" ,
192
+ // When requested target is smaller than the min cahced
193
+ // target, the fee rate of the min cached target is
194
+ // returned.
195
+ name : "API-omitted_target" ,
196
+ target : minTarget - 1 ,
197
+ expectedFeeRate : maxFeeRate ,
198
+ expectedErr : "" ,
195
199
},
196
200
{
197
- name : "valid_target_extrapolated_fee" ,
198
- target : 25 ,
199
- apiEst : 0 ,
200
- est : testFeeRate ,
201
- err : "" ,
201
+ // When the target is found, return it.
202
+ name : "valid_target" ,
203
+ target : maxTarget ,
204
+ expectedFeeRate : minFeeRate ,
205
+ expectedErr : "" ,
202
206
},
203
207
}
204
208
205
209
// Construct mock fee source for the Estimator to pull fees from.
206
210
//
207
211
// This will create a `feeByBlockTarget` map with the following values,
208
- // - 20: testFeeRate
209
- // - 100: 42, which will be floored to feeFloor.
210
- testFees := make (map [uint32 ]uint32 )
211
- for _ , tc := range testCases {
212
- if tc .apiEst != 0 {
213
- testFees [tc .target ] = tc .apiEst
214
- }
212
+ // - 2: 4000 sat/kb
213
+ // - 6: 2000 sat/kb.
214
+ feeRateResp := map [uint32 ]uint32 {
215
+ minTarget : maxFeeRate ,
216
+ maxTarget : minFeeRate ,
215
217
}
216
218
217
219
feeSource := mockSparseConfFeeSource {
218
220
url : "https://www.github.com" ,
219
- fees : testFees ,
221
+ fees : feeRateResp ,
220
222
}
221
223
222
224
estimator := NewWebAPIEstimator (feeSource , false )
223
225
224
- // Test that requesting a fee when no fees have been cached fails .
226
+ // Test that requesting a fee when no fees have been cached won't fail .
225
227
feeRate , err := estimator .EstimateFeePerKW (5 )
226
228
require .NoErrorf (t , err , "expected no error" )
227
229
require .Equalf (t , FeePerKwFloor , feeRate , "expected fee rate floor " +
228
230
"returned when no cached fee rate found" )
229
231
230
- if err := estimator .Start (); err != nil {
231
- t .Fatalf ("unable to start fee estimator, got: %v" , err )
232
- }
233
- defer estimator .Stop ()
232
+ require .NoError (t , estimator .Start (), "unable to start fee estimator" )
234
233
235
234
for _ , tc := range testCases {
236
235
tc := tc
237
236
t .Run (tc .name , func (t * testing.T ) {
238
237
est , err := estimator .EstimateFeePerKW (tc .target )
239
238
240
239
// Test an error case.
241
- if tc .err != "" {
240
+ if tc .expectedErr != "" {
242
241
require .Error (t , err , "expected error" )
243
- require .ErrorContains (t , err , tc .err )
242
+ require .ErrorContains (t , err , tc .expectedErr )
244
243
245
244
return
246
245
}
@@ -249,57 +248,78 @@ func TestWebAPIFeeEstimator(t *testing.T) {
249
248
require .NoErrorf (t , err , "error from target %v" ,
250
249
tc .target )
251
250
252
- exp := SatPerKVByte (tc .est ).FeePerKWeight ()
251
+ exp := SatPerKVByte (tc .expectedFeeRate ).FeePerKWeight ()
253
252
require .Equalf (t , exp , est , "target %v failed, fee " +
254
253
"map is %v" , tc .target , feeSource .fees )
255
254
})
256
255
}
256
+
257
+ // Stop the estimator when test ends.
258
+ require .NoError (t , estimator .Stop (), "unable to stop fee estimator" )
257
259
}
258
260
259
261
// TestGetCachedFee checks that the fee caching logic works as expected.
260
262
func TestGetCachedFee (t * testing.T ) {
261
- target := uint32 (2 )
262
- fee := uint32 (100 )
263
+ var (
264
+ minTarget uint32 = 2
265
+ maxTarget uint32 = 6
266
+
267
+ minFeeRate uint32 = 100
268
+ maxFeeRate uint32 = 1000
269
+ )
263
270
264
271
// Create a dummy estimator without WebAPIFeeSource.
265
272
estimator := NewWebAPIEstimator (nil , false )
266
273
267
274
// When the cache is empty, an error should be returned.
268
- cachedFee , err := estimator .getCachedFee (target )
275
+ cachedFee , err := estimator .getCachedFee (minTarget )
269
276
require .Zero (t , cachedFee )
270
277
require .ErrorIs (t , err , errEmptyCache )
271
278
272
- // Store a fee rate inside the cache.
273
- estimator .feeByBlockTarget [target ] = fee
279
+ // Store a fee rate inside the cache. The cache map now looks like,
280
+ // {2: 1000, 6: 100}
281
+ estimator .feeByBlockTarget = map [uint32 ]uint32 {
282
+ minTarget : maxFeeRate ,
283
+ maxTarget : minFeeRate ,
284
+ }
274
285
275
286
testCases := []struct {
276
287
name string
277
288
confTarget uint32
278
289
expectedFee uint32
279
- expectErr error
280
290
}{
281
291
{
282
292
// When the target is cached, return it.
283
293
name : "return cached fee" ,
284
- confTarget : target ,
285
- expectedFee : fee ,
286
- expectErr : nil ,
294
+ confTarget : minTarget ,
295
+ expectedFee : maxFeeRate ,
296
+ },
297
+ {
298
+ // When the target is not cached, return the next
299
+ // lowest target that's cached. In this case,
300
+ // requesting fee rate for target 7 will give the
301
+ // result for target 6.
302
+ name : "return lowest cached fee" ,
303
+ confTarget : maxTarget + 1 ,
304
+ expectedFee : minFeeRate ,
287
305
},
288
306
{
289
307
// When the target is not cached, return the next
290
- // lowest target that's cached.
308
+ // lowest target that's cached. In this case,
309
+ // requesting fee rate for target 5 will give the
310
+ // result for target 2.
291
311
name : "return next cached fee" ,
292
- confTarget : target + 1 ,
293
- expectedFee : fee ,
294
- expectErr : nil ,
312
+ confTarget : maxTarget - 1 ,
313
+ expectedFee : maxFeeRate ,
295
314
},
296
315
{
297
316
// When the target is not cached, and the next lowest
298
317
// target is not cached, return the nearest fee rate.
318
+ // In this case, requesting fee rate for target 1 will
319
+ // give the result for target 2.
299
320
name : "return highest cached fee" ,
300
- confTarget : target - 1 ,
301
- expectedFee : fee ,
302
- expectErr : nil ,
321
+ confTarget : minTarget - 1 ,
322
+ expectedFee : maxFeeRate ,
303
323
},
304
324
}
305
325
@@ -309,8 +329,8 @@ func TestGetCachedFee(t *testing.T) {
309
329
t .Run (tc .name , func (t * testing.T ) {
310
330
cachedFee , err := estimator .getCachedFee (tc .confTarget )
311
331
332
+ require .NoError (t , err )
312
333
require .Equal (t , tc .expectedFee , cachedFee )
313
- require .ErrorIs (t , err , tc .expectErr )
314
334
})
315
335
}
316
336
}
0 commit comments