Skip to content

Commit c9f0819

Browse files
authored
Implement bitcoin (#12)
* Fix Solana healthcheck * Catch websocket exceptions for EVM collector since client does not. * Implement bitcoin * Update README.md for Bitcoin
1 parent 966fe79 commit c9f0819

File tree

5 files changed

+49
-4
lines changed

5 files changed

+49
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Exporter currently supports all EVM-compatible chains. In addition, there is lim
55
- Cardano
66
- Conflux
77
- Solana
8+
- Bitcoin
89

910
# Disclaimer
1011
Please note that this tool is in the early development stage and should not be used to influence critical business decisions.

config/exporter_example/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ connection_parameters:
88
response_timeout: 5 # Timeout when waiting for a websocket message response
99
ping_interval: 6 # Liveness ping intervals
1010
ping_timeout: 3 # Liveness ping timeout
11-
collector: "evm" # This will load different collectors based on what mode exporter will run with Supported modes are: "evm", "solana", "conflux", "cardano"
11+
collector: "evm" # This will load different collectors based on what mode exporter will run with Supported modes are: "evm", "solana", "conflux", "cardano", "bitcoin"
1212
endpoints: # List of endpoints with their metadata.
1313
- ws_url: wss://example-rpc-1.com/ws # RPC Endpoint websocket endpoint (Must start with wss://)
1414
https_url: https://example-rpc-1.com/rpc # RPC Endpoint https endpoint (Must be valid https:// domain)

src/collectors/bitcoin.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import asyncio
2+
from bitcoinrpc import BitcoinRPC
3+
from helpers import strip_url
4+
from time import perf_counter
5+
from settings import cfg, logger
6+
7+
class bitcoin_collector():
8+
9+
def __init__(self, https_url, provider):
10+
self.https_url = https_url
11+
self.labels = ['https_url', 'provider', 'blockchain', 'network_name', 'network_type']
12+
self.labels_values = [
13+
https_url, provider, cfg.blockchain, cfg.network_name, cfg.network_type
14+
]
15+
16+
async def _probe(self, metrics):
17+
try:
18+
async with BitcoinRPC(self.https_url, "admin", "admin") as rpc:
19+
start = perf_counter()
20+
chain_info = await rpc.getblockchaininfo()
21+
latency = (perf_counter() - start) * 1000
22+
23+
metrics['ws_rpc_health'].add_metric(self.labels_values, True)
24+
metrics['ws_rpc_latency'].add_metric(self.labels_values, latency)
25+
metrics['ws_rpc_block_height'].add_metric(self.labels_values, chain_info['headers'])
26+
metrics['ws_rpc_total_difficulty'].add_metric(self.labels_values, chain_info['difficulty'])
27+
except Exception as exc:
28+
logger.error("Failed probing {} with error: {}".format(strip_url(self.url), exc))
29+
metrics['ws_rpc_health'].add_metric(self.labels_values, False)
30+
31+
def probe(self, metrics):
32+
asyncio.run(self._probe(metrics))

src/exporter.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from collectors.solana import solana_collector
88
from collectors.cardano import cardano_collector
99
from collectors.conflux import conflux_collector
10+
from collectors.bitcoin import bitcoin_collector
1011
from settings import logger, cfg
1112

1213

@@ -24,6 +25,8 @@ def __init__(self):
2425
self._instantiate_cardano()
2526
if cfg.isConflux():
2627
self._instantiate_conflux()
28+
if cfg.isBitcoin():
29+
self._instantiate_bitcoin()
2730

2831
def _instantiate_evm(self):
2932
for item in cfg.endpoints:
@@ -49,6 +52,12 @@ def _instantiate_cardano(self):
4952
self.collectors.append(cardano_collector(item['ws_url'], item['provider']))
5053
self.labels = self.collectors[0].labels
5154

55+
def _instantiate_bitcoin(self):
56+
for item in cfg.endpoints:
57+
logger.info("Initializing bitcoin node {}".format(strip_url(item['https_url'])))
58+
self.collectors.append(bitcoin_collector(item['https_url'], item['provider']))
59+
self.labels = self.collectors[0].labels
60+
5261
def collect(self):
5362
metrics = {
5463
"ws_rpc_health":

src/settings.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __init__(self, config_file_path: str, validation_file_path: str):
1818
self.configuration = self._load_configuration_file(config_file_path)
1919
self.blockchain = self.configuration['blockchain']
2020
# Load chain_id only if evm compatible collector
21-
if self.configuration['collector'] not in ['cardano', 'solana']:
21+
if self.configuration['collector'] not in ['cardano', 'solana', 'bitcoin']:
2222
try:
2323
self.chain_id = self.configuration['chain_id']
2424
except KeyError:
@@ -76,6 +76,9 @@ def isCardano(self) -> bool:
7676
def isConflux(self) -> bool:
7777
return self.configuration['collector'] == "conflux"
7878

79+
def isBitcoin(self) -> bool:
80+
return self.configuration['collector'] == "bitcoin"
81+
7982
def _load_configuration_file(self, path):
8083
logger.info('Loading {}'.format(path))
8184
configuration_file_schema = Schema({
@@ -88,7 +91,7 @@ def _load_configuration_file(self, path):
8891
'network_type':
8992
And(str, lambda s: s in ('Testnet', 'Mainnet')),
9093
'collector':
91-
And(str, lambda s: s in ('evm', 'cardano', 'conflux', 'solana')),
94+
And(str, lambda s: s in ('evm', 'cardano', 'conflux', 'solana', 'bitcoin')),
9295
Optional('connection_parameters'): {
9396
Optional('open_timeout'): And(int),
9497
Optional('close_timeout'): And(int),
@@ -97,7 +100,7 @@ def _load_configuration_file(self, path):
97100
Optional('ping_timeout'): And(int),
98101
},
99102
'endpoints': [{
100-
'ws_url': And(str),
103+
Optional('ws_url'): And(str),
101104
Optional('https_url'): And(str),
102105
'provider': And(str, lambda s: s in self.allowed_providers)
103106
}]

0 commit comments

Comments
 (0)