Add estimate fee and average block period prometheus metrics
This commit is contained in:
parent
aebc1c3495
commit
76a19b7f10
@ -2244,10 +2244,10 @@ type bitcoinTypeEstimatedFee struct {
|
|||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
const bitcoinTypeEstimatedFeeCacheSize = 300
|
const estimatedFeeCacheSize = 300
|
||||||
|
|
||||||
var bitcoinTypeEstimatedFeeCache [bitcoinTypeEstimatedFeeCacheSize]bitcoinTypeEstimatedFee
|
var estimatedFeeCache [estimatedFeeCacheSize]bitcoinTypeEstimatedFee
|
||||||
var bitcoinTypeEstimatedFeeConservativeCache [bitcoinTypeEstimatedFeeCacheSize]bitcoinTypeEstimatedFee
|
var estimatedFeeConservativeCache [estimatedFeeCacheSize]bitcoinTypeEstimatedFee
|
||||||
|
|
||||||
func (w *Worker) cachedBitcoinTypeEstimateFee(blocks int, conservative bool, s *bitcoinTypeEstimatedFee) (big.Int, error) {
|
func (w *Worker) cachedBitcoinTypeEstimateFee(blocks int, conservative bool, s *bitcoinTypeEstimatedFee) (big.Int, error) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
@ -2261,18 +2261,22 @@ func (w *Worker) cachedBitcoinTypeEstimateFee(blocks int, conservative bool, s *
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
s.timestamp = time.Now().Unix()
|
s.timestamp = time.Now().Unix()
|
||||||
s.fee = fee
|
s.fee = fee
|
||||||
|
w.metrics.EstimatedFee.With(common.Labels{
|
||||||
|
"blocks": strconv.Itoa(blocks),
|
||||||
|
"conservative": strconv.FormatBool(conservative),
|
||||||
|
}).Set(float64(fee.Int64()))
|
||||||
}
|
}
|
||||||
return fee, err
|
return fee, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// BitcoinTypeEstimateFee returns a fee estimation for given number of blocks
|
// EstimateFee returns a fee estimation for given number of blocks
|
||||||
// it uses 10 second cache to reduce calls to the backend
|
// it uses 10 second cache to reduce calls to the backend
|
||||||
func (w *Worker) BitcoinTypeEstimateFee(blocks int, conservative bool) (big.Int, error) {
|
func (w *Worker) EstimateFee(blocks int, conservative bool) (big.Int, error) {
|
||||||
if blocks >= bitcoinTypeEstimatedFeeCacheSize {
|
if blocks >= estimatedFeeCacheSize {
|
||||||
return w.chain.EstimateSmartFee(blocks, conservative)
|
return w.chain.EstimateSmartFee(blocks, conservative)
|
||||||
}
|
}
|
||||||
if conservative {
|
if conservative {
|
||||||
return w.cachedBitcoinTypeEstimateFee(blocks, conservative, &bitcoinTypeEstimatedFeeConservativeCache[blocks])
|
return w.cachedBitcoinTypeEstimateFee(blocks, conservative, &estimatedFeeConservativeCache[blocks])
|
||||||
}
|
}
|
||||||
return w.cachedBitcoinTypeEstimateFee(blocks, conservative, &bitcoinTypeEstimatedFeeCache[blocks])
|
return w.cachedBitcoinTypeEstimateFee(blocks, conservative, &estimatedFeeCache[blocks])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -68,6 +70,7 @@ type InternalState struct {
|
|||||||
BestHeight uint32 `json:"bestHeight"`
|
BestHeight uint32 `json:"bestHeight"`
|
||||||
LastSync time.Time `json:"lastSync"`
|
LastSync time.Time `json:"lastSync"`
|
||||||
BlockTimes []uint32 `json:"-"`
|
BlockTimes []uint32 `json:"-"`
|
||||||
|
AvgBlockPeriod uint32 `json:"-"`
|
||||||
|
|
||||||
IsMempoolSynchronized bool `json:"isMempoolSynchronized"`
|
IsMempoolSynchronized bool `json:"isMempoolSynchronized"`
|
||||||
MempoolSize int `json:"mempoolSize"`
|
MempoolSize int `json:"mempoolSize"`
|
||||||
@ -77,7 +80,6 @@ type InternalState struct {
|
|||||||
|
|
||||||
UtxoChecked bool `json:"utxoChecked"`
|
UtxoChecked bool `json:"utxoChecked"`
|
||||||
|
|
||||||
// store only the historical state, not the current state of the fiat rates in DB
|
|
||||||
HasFiatRates bool `json:"-"`
|
HasFiatRates bool `json:"-"`
|
||||||
HasTokenFiatRates bool `json:"-"`
|
HasTokenFiatRates bool `json:"-"`
|
||||||
HistoricalFiatRatesTime time.Time `json:"historicalFiatRatesTime"`
|
HistoricalFiatRatesTime time.Time `json:"historicalFiatRatesTime"`
|
||||||
@ -208,11 +210,23 @@ func (is *InternalState) GetBlockTime(height uint32) uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendBlockTime appends block time to BlockTimes
|
// SetBlockTimes initializes BlockTimes array, returns AvgBlockPeriod
|
||||||
func (is *InternalState) AppendBlockTime(time uint32) {
|
func (is *InternalState) SetBlockTimes(blockTimes []uint32) uint32 {
|
||||||
|
is.mux.Lock()
|
||||||
|
defer is.mux.Unlock()
|
||||||
|
is.BlockTimes = blockTimes
|
||||||
|
is.computeAvgBlockPeriod()
|
||||||
|
glog.Info("set ", len(is.BlockTimes), " block times, average block period ", is.AvgBlockPeriod, "s")
|
||||||
|
return is.AvgBlockPeriod
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendBlockTime appends block time to BlockTimes, returns AvgBlockPeriod
|
||||||
|
func (is *InternalState) AppendBlockTime(time uint32) uint32 {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
is.BlockTimes = append(is.BlockTimes, time)
|
is.BlockTimes = append(is.BlockTimes, time)
|
||||||
|
is.computeAvgBlockPeriod()
|
||||||
|
return is.AvgBlockPeriod
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveLastBlockTimes removes last times from BlockTimes
|
// RemoveLastBlockTimes removes last times from BlockTimes
|
||||||
@ -223,6 +237,7 @@ func (is *InternalState) RemoveLastBlockTimes(count int) {
|
|||||||
count = len(is.BlockTimes)
|
count = len(is.BlockTimes)
|
||||||
}
|
}
|
||||||
is.BlockTimes = is.BlockTimes[:len(is.BlockTimes)-count]
|
is.BlockTimes = is.BlockTimes[:len(is.BlockTimes)-count]
|
||||||
|
is.computeAvgBlockPeriod()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockHeightOfTime returns block height of the first block with time greater or equal to the given time or MaxUint32 if no such block
|
// GetBlockHeightOfTime returns block height of the first block with time greater or equal to the given time or MaxUint32 if no such block
|
||||||
@ -246,6 +261,25 @@ func (is *InternalState) GetBlockHeightOfTime(time uint32) uint32 {
|
|||||||
return uint32(height)
|
return uint32(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const avgBlockPeriodSample = 100
|
||||||
|
|
||||||
|
// Avg100BlocksPeriod returns average period of the last 100 blocks in seconds
|
||||||
|
func (is *InternalState) GetAvgBlockPeriod() uint32 {
|
||||||
|
is.mux.Lock()
|
||||||
|
defer is.mux.Unlock()
|
||||||
|
return is.AvgBlockPeriod
|
||||||
|
}
|
||||||
|
|
||||||
|
// computeAvgBlockPeriod returns computes average of the last 100 blocks in seconds
|
||||||
|
func (is *InternalState) computeAvgBlockPeriod() {
|
||||||
|
last := len(is.BlockTimes) - 1
|
||||||
|
first := last - avgBlockPeriodSample - 1
|
||||||
|
if first < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
is.AvgBlockPeriod = (is.BlockTimes[last] - is.BlockTimes[first]) / avgBlockPeriodSample
|
||||||
|
}
|
||||||
|
|
||||||
// SetBackendInfo sets new BackendInfo
|
// SetBackendInfo sets new BackendInfo
|
||||||
func (is *InternalState) SetBackendInfo(bi *BackendInfo) {
|
func (is *InternalState) SetBackendInfo(bi *BackendInfo) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
|
|||||||
@ -24,6 +24,8 @@ type Metrics struct {
|
|||||||
IndexDBSize prometheus.Gauge
|
IndexDBSize prometheus.Gauge
|
||||||
ExplorerViews *prometheus.CounterVec
|
ExplorerViews *prometheus.CounterVec
|
||||||
MempoolSize prometheus.Gauge
|
MempoolSize prometheus.Gauge
|
||||||
|
EstimatedFee *prometheus.GaugeVec
|
||||||
|
AvgBlockPeriod prometheus.Gauge
|
||||||
DbColumnRows *prometheus.GaugeVec
|
DbColumnRows *prometheus.GaugeVec
|
||||||
DbColumnSize *prometheus.GaugeVec
|
DbColumnSize *prometheus.GaugeVec
|
||||||
BlockbookAppInfo *prometheus.GaugeVec
|
BlockbookAppInfo *prometheus.GaugeVec
|
||||||
@ -169,6 +171,21 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
metrics.EstimatedFee = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "blockbook_estimated_fee",
|
||||||
|
Help: "Estimated fee per byte (gas) for number of blocks",
|
||||||
|
ConstLabels: Labels{"coin": coin},
|
||||||
|
},
|
||||||
|
[]string{"blocks", "conservative"},
|
||||||
|
)
|
||||||
|
metrics.AvgBlockPeriod = prometheus.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "blockbook_avg_block_period",
|
||||||
|
Help: "Average period of mining of last 100 blocks in seconds",
|
||||||
|
ConstLabels: Labels{"coin": coin},
|
||||||
|
},
|
||||||
|
)
|
||||||
metrics.DbColumnRows = prometheus.NewGaugeVec(
|
metrics.DbColumnRows = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Name: "blockbook_dbcolumn_rows",
|
Name: "blockbook_dbcolumn_rows",
|
||||||
@ -209,7 +226,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
)
|
)
|
||||||
metrics.ExplorerPendingRequests = prometheus.NewGaugeVec(
|
metrics.ExplorerPendingRequests = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Name: "blockbook_explorer_pending_reqests",
|
Name: "blockbook_explorer_pending_requests",
|
||||||
Help: "Number of unfinished requests in explorer interface",
|
Help: "Number of unfinished requests in explorer interface",
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
@ -217,7 +234,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
)
|
)
|
||||||
metrics.WebsocketPendingRequests = prometheus.NewGaugeVec(
|
metrics.WebsocketPendingRequests = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Name: "blockbook_websocket_pending_reqests",
|
Name: "blockbook_websocket_pending_requests",
|
||||||
Help: "Number of unfinished requests in websocket interface",
|
Help: "Number of unfinished requests in websocket interface",
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
@ -225,7 +242,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
)
|
)
|
||||||
metrics.SocketIOPendingRequests = prometheus.NewGaugeVec(
|
metrics.SocketIOPendingRequests = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Name: "blockbook_socketio_pending_reqests",
|
Name: "blockbook_socketio_pending_requests",
|
||||||
Help: "Number of unfinished requests in socketio interface",
|
Help: "Number of unfinished requests in socketio interface",
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -403,11 +403,14 @@ func (b *BulkConnect) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var err error
|
bt, err := b.d.loadBlockTimes()
|
||||||
b.d.is.BlockTimes, err = b.d.loadBlockTimes()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
avg := b.d.is.SetBlockTimes(bt)
|
||||||
|
if b.d.metrics != nil {
|
||||||
|
b.d.metrics.AvgBlockPeriod.Set(float64(avg))
|
||||||
|
}
|
||||||
|
|
||||||
if err := b.d.SetInconsistentState(false); err != nil {
|
if err := b.d.SetInconsistentState(false); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -380,7 +380,10 @@ func (d *RocksDB) ConnectBlock(block *bchain.Block) error {
|
|||||||
if err := d.WriteBatch(wb); err != nil {
|
if err := d.WriteBatch(wb); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.is.AppendBlockTime(uint32(block.Time))
|
avg := d.is.AppendBlockTime(uint32(block.Time))
|
||||||
|
if d.metrics != nil {
|
||||||
|
d.metrics.AvgBlockPeriod.Set(float64(avg))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1631,7 +1634,6 @@ func (d *RocksDB) loadBlockTimes() ([]uint32, error) {
|
|||||||
}
|
}
|
||||||
times = append(times, time)
|
times = append(times, time)
|
||||||
}
|
}
|
||||||
glog.Info("loaded ", len(times), " block times")
|
|
||||||
return times, nil
|
return times, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1699,10 +1701,15 @@ func (d *RocksDB) LoadInternalState(rpcCoin string) (*common.InternalState, erro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
is.DbColumns = nc
|
is.DbColumns = nc
|
||||||
is.BlockTimes, err = d.loadBlockTimes()
|
bt, err := d.loadBlockTimes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
avg := is.SetBlockTimes(bt)
|
||||||
|
if d.metrics != nil {
|
||||||
|
d.metrics.AvgBlockPeriod.Set(float64(avg))
|
||||||
|
}
|
||||||
|
|
||||||
// after load, reset the synchronization data
|
// after load, reset the synchronization data
|
||||||
is.IsSynchronized = false
|
is.IsSynchronized = false
|
||||||
is.IsMempoolSynchronized = false
|
is.IsMempoolSynchronized = false
|
||||||
|
|||||||
@ -638,11 +638,15 @@ func (s *WebsocketServer) estimateFee(c *websocketChannel, params []byte) (inter
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sg := strconv.FormatUint(gas, 10)
|
sg := strconv.FormatUint(gas, 10)
|
||||||
for i, b := range r.Blocks {
|
b := 1
|
||||||
fee, err := s.chain.EstimateSmartFee(b, true)
|
if len(r.Blocks) > 0 {
|
||||||
|
b = r.Blocks[0]
|
||||||
|
}
|
||||||
|
fee, err := s.api.EstimateFee(b, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for i := range r.Blocks {
|
||||||
res[i].FeePerUnit = fee.String()
|
res[i].FeePerUnit = fee.String()
|
||||||
res[i].FeeLimit = sg
|
res[i].FeeLimit = sg
|
||||||
fee.Mul(&fee, new(big.Int).SetUint64(gas))
|
fee.Mul(&fee, new(big.Int).SetUint64(gas))
|
||||||
@ -666,7 +670,7 @@ func (s *WebsocketServer) estimateFee(c *websocketChannel, params []byte) (inter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, b := range r.Blocks {
|
for i, b := range r.Blocks {
|
||||||
fee, err := s.api.BitcoinTypeEstimateFee(b, conservative)
|
fee, err := s.api.EstimateFee(b, conservative)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user