mirror of
https://github.com/trezor/blockbook.git
synced 2026-02-20 00:51:39 +01:00
eth_call metrics
This commit is contained in:
@@ -154,6 +154,10 @@ func init() {
|
||||
BlockChainFactories["Base Archive"] = base.NewBaseRPC
|
||||
}
|
||||
|
||||
type metricsSetter interface {
|
||||
SetMetrics(*common.Metrics)
|
||||
}
|
||||
|
||||
// NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin
|
||||
func NewBlockChain(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics) (bchain.BlockChain, bchain.Mempool, error) {
|
||||
data, err := os.ReadFile(configfile)
|
||||
@@ -173,6 +177,9 @@ func NewBlockChain(coin string, configfile string, pushHandler func(bchain.Notif
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if withMetrics, ok := bc.(metricsSetter); ok {
|
||||
withMetrics.SetMetrics(metrics)
|
||||
}
|
||||
err = bc.Initialize()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -290,12 +290,14 @@ func (b *EthereumRPC) EthereumTypeRpcCallAtBlock(data, to, from string, blockNum
|
||||
args["from"] = from
|
||||
}
|
||||
|
||||
b.observeEthCall("single", 1)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
var r string
|
||||
blockArg := bchain.ToBlockNumArg(blockNumber)
|
||||
err := b.RPC.CallContext(ctx, &r, "eth_call", args, blockArg)
|
||||
if err != nil {
|
||||
b.observeEthCallError("single", "rpc")
|
||||
return "", err
|
||||
}
|
||||
return r, nil
|
||||
@@ -373,6 +375,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractBalanceAtBlock(addrDesc, contr
|
||||
}
|
||||
r := parseSimpleNumericProperty(data)
|
||||
if r == nil {
|
||||
b.observeEthCallError("single", "invalid")
|
||||
return nil, errors.New("Invalid balance")
|
||||
}
|
||||
return r, nil
|
||||
@@ -445,14 +448,18 @@ func (b *EthereumRPC) erc20BalancesBatchAtBlock(batcher batchCaller, callData st
|
||||
Result: &results[i],
|
||||
}
|
||||
}
|
||||
b.observeEthCall("batch", len(contractDescs))
|
||||
b.observeEthCallBatch(len(contractDescs))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
if err := batcher.BatchCallContext(ctx, batch); err != nil {
|
||||
b.observeEthCallError("batch", "rpc")
|
||||
return nil, err
|
||||
}
|
||||
balances := make([]*big.Int, len(contractDescs))
|
||||
for i := range batch {
|
||||
if batch[i].Error != nil {
|
||||
b.observeEthCallError("batch", "elem")
|
||||
glog.Warningf("erc20 batch eth_call failed for %s: %v", hexutil.Encode(contractDescs[i]), batch[i].Error)
|
||||
// In case of batch failure, retry missing/failed elements as single calls.
|
||||
data, err := b.EthereumTypeRpcCallAtBlock(callData, hexutil.Encode(contractDescs[i]), "", blockNumber)
|
||||
@@ -462,6 +469,7 @@ func (b *EthereumRPC) erc20BalancesBatchAtBlock(batcher batchCaller, callData st
|
||||
}
|
||||
balances[i] = parseSimpleNumericProperty(data)
|
||||
if balances[i] == nil {
|
||||
b.observeEthCallError("single", "invalid")
|
||||
glog.Warningf("erc20 single eth_call invalid result for %s: %q", hexutil.Encode(contractDescs[i]), data)
|
||||
}
|
||||
continue
|
||||
@@ -469,6 +477,7 @@ func (b *EthereumRPC) erc20BalancesBatchAtBlock(batcher batchCaller, callData st
|
||||
// Leave nil on parse failures so callers can retry per contract if needed.
|
||||
balances[i] = parseSimpleNumericProperty(results[i])
|
||||
if balances[i] == nil {
|
||||
b.observeEthCallError("batch", "invalid")
|
||||
glog.Warningf("erc20 batch eth_call invalid result for %s: %q", hexutil.Encode(contractDescs[i]), results[i])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ type EthereumRPC struct {
|
||||
NewTx bchain.EVMNewTxSubscriber
|
||||
newTxSubscription bchain.EVMClientSubscription
|
||||
ChainConfig *Configuration
|
||||
metrics *common.Metrics
|
||||
supportedStakingPools []string
|
||||
stakingPoolNames []string
|
||||
stakingPoolContracts []string
|
||||
@@ -161,6 +162,31 @@ func NewEthereumRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) SetMetrics(metrics *common.Metrics) {
|
||||
b.metrics = metrics
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) observeEthCall(mode string, count int) {
|
||||
if b.metrics == nil || count <= 0 {
|
||||
return
|
||||
}
|
||||
b.metrics.EthCallRequests.With(common.Labels{"mode": mode}).Add(float64(count))
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) observeEthCallError(mode, errType string) {
|
||||
if b.metrics == nil {
|
||||
return
|
||||
}
|
||||
b.metrics.EthCallErrors.With(common.Labels{"mode": mode, "type": errType}).Inc()
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) observeEthCallBatch(size int) {
|
||||
if b.metrics == nil || size <= 0 {
|
||||
return
|
||||
}
|
||||
b.metrics.EthCallBatchSize.Observe(float64(size))
|
||||
}
|
||||
|
||||
// EnsureSameRPCHost validates that both RPC URLs point to the same host.
|
||||
func EnsureSameRPCHost(httpURL, wsURL string) error {
|
||||
if httpURL == "" || wsURL == "" {
|
||||
|
||||
@@ -20,6 +20,9 @@ type Metrics struct {
|
||||
MempoolResyncDuration prometheus.Histogram
|
||||
TxCacheEfficiency *prometheus.CounterVec
|
||||
RPCLatency *prometheus.HistogramVec
|
||||
EthCallRequests *prometheus.CounterVec
|
||||
EthCallErrors *prometheus.CounterVec
|
||||
EthCallBatchSize prometheus.Histogram
|
||||
IndexResyncErrors *prometheus.CounterVec
|
||||
IndexDBSize prometheus.Gauge
|
||||
ExplorerViews *prometheus.CounterVec
|
||||
@@ -149,6 +152,30 @@ func GetMetrics(coin string) (*Metrics, error) {
|
||||
},
|
||||
[]string{"method", "error"},
|
||||
)
|
||||
metrics.EthCallRequests = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "blockbook_eth_call_requests",
|
||||
Help: "Total number of eth_call requests by mode",
|
||||
ConstLabels: Labels{"coin": coin},
|
||||
},
|
||||
[]string{"mode"},
|
||||
)
|
||||
metrics.EthCallErrors = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "blockbook_eth_call_errors",
|
||||
Help: "Total number of eth_call errors by mode and type",
|
||||
ConstLabels: Labels{"coin": coin},
|
||||
},
|
||||
[]string{"mode", "type"},
|
||||
)
|
||||
metrics.EthCallBatchSize = prometheus.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "blockbook_eth_call_batch_size",
|
||||
Help: "Number of eth_call items per batch request",
|
||||
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200},
|
||||
ConstLabels: Labels{"coin": coin},
|
||||
},
|
||||
)
|
||||
metrics.IndexResyncErrors = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "blockbook_index_resync_errors",
|
||||
|
||||
Reference in New Issue
Block a user