- Adding self restart when repeated error occurs with backend rpc connection - renamed package name to reflect correctly
136 lines
3.4 KiB
Go
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)
|
|
}
|