From af0711dc12e5d79913e512fa5483d94b2758fcd6 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Mon, 3 May 2021 23:10:20 +0200 Subject: [PATCH] Cache estimateFee call for bitcoin type coin --- api/worker.go | 47 +++++++++++++++++++++++++++++ server/public_test.go | 70 ++++++++++++++++++++++++++----------------- server/websocket.go | 2 +- 3 files changed, 90 insertions(+), 29 deletions(-) diff --git a/api/worker.go b/api/worker.go index 50372e0d..639d8eea 100644 --- a/api/worker.go +++ b/api/worker.go @@ -1821,3 +1821,50 @@ func (w *Worker) GetMempool(page int, itemsOnPage int) (*MempoolTxids, error) { } return r, nil } + +type bitcoinTypeEstimatedFee struct { + accessed int64 + fee big.Int +} + +const bitcoinTypeEstimatedFeeCacheSize = 250 + +var bitcoinTypeEstimatedFeeCache [bitcoinTypeEstimatedFeeCacheSize]bitcoinTypeEstimatedFee +var bitcoinTypeEstimatedFeeConservativeCache [bitcoinTypeEstimatedFeeCacheSize]bitcoinTypeEstimatedFee + +// BitcoinTypeEstimateFee returns a fee estimation for given number of blocks +// it uses 5 second cache to reduce calls to the backend +func (w *Worker) BitcoinTypeEstimateFee(blocks int, conservative bool) (big.Int, error) { + if blocks >= bitcoinTypeEstimatedFeeCacheSize { + return w.chain.EstimateSmartFee(blocks, conservative) + } + // 5 seconds cache + threshold := time.Now().Unix() - 5 + if conservative { + cached := bitcoinTypeEstimatedFeeConservativeCache[blocks] + if cached.accessed >= threshold { + return cached.fee, nil + } + fee, err := w.chain.EstimateSmartFee(blocks, conservative) + if err == nil { + bitcoinTypeEstimatedFeeConservativeCache[blocks] = bitcoinTypeEstimatedFee{ + accessed: time.Now().Unix(), + fee: fee, + } + } + return fee, err + } else { + cached := bitcoinTypeEstimatedFeeCache[blocks] + if cached.accessed >= threshold { + return cached.fee, nil + } + fee, err := w.chain.EstimateSmartFee(blocks, conservative) + if err == nil { + bitcoinTypeEstimatedFeeCache[blocks] = bitcoinTypeEstimatedFee{ + accessed: time.Now().Unix(), + fee: fee, + } + } + return fee, err + } +} diff --git a/server/public_test.go b/server/public_test.go index 161ca66f..aea21e19 100644 --- a/server/public_test.go +++ b/server/public_test.go @@ -1155,6 +1155,20 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { }, want: `{"id":"10","data":[{"feePerTx":"246","feePerUnit":"199"},{"feePerTx":"616","feePerUnit":"499"},{"feePerTx":"1233","feePerUnit":"999"},{"feePerTx":"2467","feePerUnit":"1999"}]}`, }, + { + name: "websocket estimateFee second time, from cache", + req: websocketReq{ + Method: "estimateFee", + Params: map[string]interface{}{ + "blocks": []int{2, 5, 10, 20}, + "specific": map[string]interface{}{ + "conservative": false, + "txsize": 1234, + }, + }, + }, + want: `{"id":"11","data":[{"feePerTx":"246","feePerUnit":"199"},{"feePerTx":"616","feePerUnit":"499"},{"feePerTx":"1233","feePerUnit":"999"},{"feePerTx":"2467","feePerUnit":"1999"}]}`, + }, { name: "websocket sendTransaction", req: websocketReq{ @@ -1163,21 +1177,21 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "hex": "123456", }, }, - want: `{"id":"11","data":{"result":"9876"}}`, + want: `{"id":"12","data":{"result":"9876"}}`, }, { name: "websocket subscribeNewBlock", req: websocketReq{ Method: "subscribeNewBlock", }, - want: `{"id":"12","data":{"subscribed":true}}`, + want: `{"id":"13","data":{"subscribed":true}}`, }, { name: "websocket unsubscribeNewBlock", req: websocketReq{ Method: "unsubscribeNewBlock", }, - want: `{"id":"13","data":{"subscribed":false}}`, + want: `{"id":"14","data":{"subscribed":false}}`, }, { name: "websocket subscribeAddresses", @@ -1187,21 +1201,21 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "addresses": []string{dbtestdata.Addr1, dbtestdata.Addr2}, }, }, - want: `{"id":"14","data":{"subscribed":true}}`, + want: `{"id":"15","data":{"subscribed":true}}`, }, { name: "websocket unsubscribeAddresses", req: websocketReq{ Method: "unsubscribeAddresses", }, - want: `{"id":"15","data":{"subscribed":false}}`, + want: `{"id":"16","data":{"subscribed":false}}`, }, { name: "websocket ping", req: websocketReq{ Method: "ping", }, - want: `{"id":"16","data":{}}`, + want: `{"id":"17","data":{}}`, }, { name: "websocket getCurrentFiatRates all currencies", @@ -1211,7 +1225,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{}, }, }, - want: `{"id":"17","data":{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`, + want: `{"id":"18","data":{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`, }, { name: "websocket getCurrentFiatRates usd", @@ -1221,7 +1235,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{"usd"}, }, }, - want: `{"id":"18","data":{"ts":1574346615,"rates":{"usd":7914.5}}}`, + want: `{"id":"19","data":{"ts":1574346615,"rates":{"usd":7914.5}}}`, }, { name: "websocket getCurrentFiatRates eur", @@ -1231,7 +1245,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{"eur"}, }, }, - want: `{"id":"19","data":{"ts":1574346615,"rates":{"eur":7134.1}}}`, + want: `{"id":"20","data":{"ts":1574346615,"rates":{"eur":7134.1}}}`, }, { name: "websocket getCurrentFiatRates incorrect currency", @@ -1241,7 +1255,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{"does-not-exist"}, }, }, - want: `{"id":"20","data":{"ts":1574346615,"rates":{"does-not-exist":-1}}}`, + want: `{"id":"21","data":{"ts":1574346615,"rates":{"does-not-exist":-1}}}`, }, { name: "websocket getFiatRatesForTimestamps missing date", @@ -1251,7 +1265,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{"usd"}, }, }, - want: `{"id":"21","data":{"error":{"message":"No timestamps provided"}}}`, + want: `{"id":"22","data":{"error":{"message":"No timestamps provided"}}}`, }, { name: "websocket getFiatRatesForTimestamps incorrect date", @@ -1262,7 +1276,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []string{"yesterday"}, }, }, - want: `{"id":"22","data":{"error":{"message":"json: cannot unmarshal string into Go struct field .timestamps of type int64"}}}`, + want: `{"id":"23","data":{"error":{"message":"json: cannot unmarshal string into Go struct field .timestamps of type int64"}}}`, }, { name: "websocket getFiatRatesForTimestamps empty currency", @@ -1273,7 +1287,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{""}, }, }, - want: `{"id":"23","data":{"tickers":[{"ts":7885693815,"rates":{}}]}}`, + want: `{"id":"24","data":{"tickers":[{"ts":7885693815,"rates":{}}]}}`, }, { name: "websocket getFiatRatesForTimestamps incorrect (future) date", @@ -1284,7 +1298,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{7885693815}, }, }, - want: `{"id":"24","data":{"tickers":[{"ts":7885693815,"rates":{"usd":-1}}]}}`, + want: `{"id":"25","data":{"tickers":[{"ts":7885693815,"rates":{"usd":-1}}]}}`, }, { name: "websocket getFiatRatesForTimestamps exact date", @@ -1295,7 +1309,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{1574346615}, }, }, - want: `{"id":"25","data":{"tickers":[{"ts":1574346615,"rates":{"usd":7914.5}}]}}`, + want: `{"id":"26","data":{"tickers":[{"ts":1574346615,"rates":{"usd":7914.5}}]}}`, }, { name: "websocket getFiatRatesForTimestamps closest date, eur", @@ -1306,7 +1320,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{1521507600}, }, }, - want: `{"id":"26","data":{"tickers":[{"ts":1521511200,"rates":{"eur":1300}}]}}`, + want: `{"id":"27","data":{"tickers":[{"ts":1521511200,"rates":{"eur":1300}}]}}`, }, { name: "websocket getFiatRatesForTimestamps multiple timestamps usd", @@ -1317,7 +1331,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{1570346615, 1574346615}, }, }, - want: `{"id":"27","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}}]}}`, + want: `{"id":"28","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}}]}}`, }, { name: "websocket getFiatRatesForTimestamps multiple timestamps eur", @@ -1328,7 +1342,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{1570346615, 1574346615}, }, }, - want: `{"id":"28","data":{"tickers":[{"ts":1574344800,"rates":{"eur":7100}},{"ts":1574346615,"rates":{"eur":7134.1}}]}}`, + want: `{"id":"29","data":{"tickers":[{"ts":1574344800,"rates":{"eur":7100}},{"ts":1574346615,"rates":{"eur":7134.1}}]}}`, }, { name: "websocket getFiatRatesForTimestamps multiple timestamps with an error", @@ -1339,7 +1353,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{1570346615, 1574346615, 2000000000}, }, }, - want: `{"id":"29","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}},{"ts":2000000000,"rates":{"usd":-1}}]}}`, + want: `{"id":"30","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}},{"ts":2000000000,"rates":{"usd":-1}}]}}`, }, { name: "websocket getFiatRatesForTimestamps multiple errors", @@ -1350,7 +1364,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamps": []int64{7832854800, 2000000000}, }, }, - want: `{"id":"30","data":{"tickers":[{"ts":7832854800,"rates":{"usd":-1}},{"ts":2000000000,"rates":{"usd":-1}}]}}`, + want: `{"id":"31","data":{"tickers":[{"ts":7832854800,"rates":{"usd":-1}},{"ts":2000000000,"rates":{"usd":-1}}]}}`, }, { name: "websocket getTickersList", @@ -1360,7 +1374,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "timestamp": 1570346615, }, }, - want: `{"id":"31","data":{"ts":1574344800,"available_currencies":["eur","usd"]}}`, + want: `{"id":"32","data":{"ts":1574344800,"available_currencies":["eur","usd"]}}`, }, { name: "websocket getBalanceHistory Addr2", @@ -1370,7 +1384,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "descriptor": "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", }, }, - want: `{"id":"32","data":[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1303,"usd":2003}}]}`, + want: `{"id":"33","data":[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1303,"usd":2003}}]}`, }, { name: "websocket getBalanceHistory xpub", @@ -1380,7 +1394,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "descriptor": dbtestdata.Xpub, }, }, - want: `{"id":"33","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1303,"usd":2003}}]}`, + want: `{"id":"34","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1303,"usd":2003}}]}`, }, { name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[usd]", @@ -1393,7 +1407,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{"usd"}, }, }, - want: `{"id":"34","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"usd":2001}}]}`, + want: `{"id":"35","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"usd":2001}}]}`, }, { name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[usd, eur, incorrect]", @@ -1406,7 +1420,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{"usd", "eur", "incorrect"}, }, }, - want: `{"id":"35","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"incorrect":-1,"usd":2001}}]}`, + want: `{"id":"36","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"incorrect":-1,"usd":2001}}]}`, }, { name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[]", @@ -1419,21 +1433,21 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "currencies": []string{}, }, }, - want: `{"id":"36","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}}]}`, + want: `{"id":"37","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}}]}`, }, { name: "websocket subscribeNewTransaction", req: websocketReq{ Method: "subscribeNewTransaction", }, - want: `{"id":"37","data":{"subscribed":false,"message":"subscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, + want: `{"id":"38","data":{"subscribed":false,"message":"subscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, }, { name: "websocket unsubscribeNewTransaction", req: websocketReq{ Method: "unsubscribeNewTransaction", }, - want: `{"id":"38","data":{"subscribed":false,"message":"unsubscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, + want: `{"id":"39","data":{"subscribed":false,"message":"unsubscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, }, } diff --git a/server/websocket.go b/server/websocket.go index 9e160250..726ea585 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -643,7 +643,7 @@ func (s *WebsocketServer) estimateFee(c *websocketChannel, params []byte) (inter } } for i, b := range r.Blocks { - fee, err := s.chain.EstimateSmartFee(b, conservative) + fee, err := s.api.BitcoinTypeEstimateFee(b, conservative) if err != nil { return nil, err }