blockbook/bchain/coins/btc/mempoolspace.go
Sai Raj 49ca2ba2cf Self restart on repeated error and package name
- Adding self restart when repeated error occurs with backend rpc connection

- renamed package name to reflect correctly
2024-07-01 22:20:48 -04:00

136 lines
3.4 KiB
Go

package btc
import (
"bytes"
"encoding/json"
"net/http"
"strconv"
"time"
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/ranchimall/blockbook/bchain"
)
// https://mempool.space/api/v1/fees/recommended returns
// {"fastestFee":41,"halfHourFee":39,"hourFee":36,"economyFee":36,"minimumFee":20}
type mempoolSpaceFeeResult struct {
FastestFee int `json:"fastestFee"`
HalfHourFee int `json:"halfHourFee"`
HourFee int `json:"hourFee"`
EconomyFee int `json:"economyFee"`
MinimumFee int `json:"minimumFee"`
}
type mempoolSpaceFeeParams struct {
URL string `json:"url"`
PeriodSeconds int `periodSeconds:"url"`
}
type mempoolSpaceFeeProvider struct {
*alternativeFeeProvider
params mempoolSpaceFeeParams
}
// NewMempoolSpaceFee initializes https://mempool.space provider
func NewMempoolSpaceFee(chain bchain.BlockChain, params string) (alternativeFeeProviderInterface, error) {
p := &mempoolSpaceFeeProvider{alternativeFeeProvider: &alternativeFeeProvider{}}
err := json.Unmarshal([]byte(params), &p.params)
if err != nil {
return nil, err
}
if p.params.URL == "" || p.params.PeriodSeconds == 0 {
return nil, errors.New("NewWhatTheFee: Missing parameters")
}
p.chain = chain
go p.mempoolSpaceFeeDownloader()
return p, nil
}
func (p *mempoolSpaceFeeProvider) mempoolSpaceFeeDownloader() {
period := time.Duration(p.params.PeriodSeconds) * time.Second
timer := time.NewTimer(period)
counter := 0
for {
var data mempoolSpaceFeeResult
err := p.mempoolSpaceFeeGetData(&data)
if err != nil {
glog.Error("mempoolSpaceFeeGetData ", err)
} else {
if p.mempoolSpaceFeeProcessData(&data) {
if counter%60 == 0 {
p.compareToDefault()
}
counter++
}
}
<-timer.C
timer.Reset(period)
}
}
func (p *mempoolSpaceFeeProvider) mempoolSpaceFeeProcessData(data *mempoolSpaceFeeResult) bool {
if data.MinimumFee == 0 || data.EconomyFee == 0 || data.HourFee == 0 || data.HalfHourFee == 0 || data.FastestFee == 0 {
glog.Errorf("mempoolSpaceFeeProcessData: invalid data %+v", data)
return false
}
p.mux.Lock()
defer p.mux.Unlock()
p.fees = make([]alternativeFeeProviderFee, 5)
// map mempoool.space fees to blocks
// FastestFee is for 1 block
p.fees[0] = alternativeFeeProviderFee{
blocks: 1,
feePerKB: data.FastestFee * 1000,
}
// HalfHourFee is for 2-6 blocks
p.fees[1] = alternativeFeeProviderFee{
blocks: 6,
feePerKB: data.HalfHourFee * 1000,
}
// HourFee is for 7-36 blocks
p.fees[2] = alternativeFeeProviderFee{
blocks: 36,
feePerKB: data.HourFee * 1000,
}
// EconomyFee is for 37-200 blocks
p.fees[3] = alternativeFeeProviderFee{
blocks: 500,
feePerKB: data.EconomyFee * 1000,
}
// MinimumFee is for over 500 blocks
p.fees[4] = alternativeFeeProviderFee{
blocks: 1000,
feePerKB: data.MinimumFee * 1000,
}
p.lastSync = time.Now()
// glog.Infof("mempoolSpaceFees: %+v", p.fees)
return true
}
func (p *mempoolSpaceFeeProvider) mempoolSpaceFeeGetData(res interface{}) error {
var httpData []byte
httpReq, err := http.NewRequest("GET", p.params.URL, bytes.NewBuffer(httpData))
if err != nil {
return err
}
httpRes, err := http.DefaultClient.Do(httpReq)
if httpRes != nil {
defer httpRes.Body.Close()
}
if err != nil {
return err
}
if httpRes.StatusCode != http.StatusOK {
return errors.New(p.params.URL + " returned status " + strconv.Itoa(httpRes.StatusCode))
}
return safeDecodeResponse(httpRes.Body, &res)
}