Files
cpu-miner/prototype/rpc.py

102 lines
3.2 KiB
Python

import logging
from bitcoinrpc.authproxy import AuthServiceProxy
import config
log = logging.getLogger(__name__)
def connect_rpc() -> AuthServiceProxy:
"""Create an RPC connection to the Bitcoin node."""
return AuthServiceProxy(
f"http://{config.RPC_USER}:{config.RPC_PASSWORD}@{config.RPC_HOST}:{config.RPC_PORT}"
)
def test_rpc_connection() -> None:
"""Check the connection and show basic blockchain information."""
log.info("Checking RPC connection")
try:
info = connect_rpc().getblockchaininfo()
log.info(
"RPC connection successful - chain=%s, blocks=%d, difficulty=%s",
info["chain"], info["blocks"], info["difficulty"],
)
except Exception:
log.exception("RPC connection error")
raise
def get_best_block_hash(rpc) -> str | None:
"""Fetch the most recent block hash."""
try:
h = rpc.getbestblockhash()
log.debug("Best block hash: %s", h)
return h
except Exception as e:
log.error("RPC error getbestblockhash: %s", e)
return None
def get_block_template(rpc) -> dict | None:
"""Request a block template with SegWit support."""
try:
tpl = rpc.getblocktemplate({"rules": ["segwit"]})
log.debug("Template received - height=%d, tx=%d", tpl["height"], len(tpl["transactions"]))
return tpl
except Exception as e:
log.error("RPC error getblocktemplate: %s", e)
return None
def ensure_witness_data(rpc, template: dict) -> None:
"""
Enrich template transactions with full witness data.
Use a single HTTP batch call to reduce latency versus N single requests.
"""
txs = template["transactions"]
if not txs:
return
# JSON-RPC batch call: one HTTP request for all transactions
try:
batch = [["getrawtransaction", tx["txid"], False] for tx in txs]
results = rpc._batch(batch)
raw_map = {
txs[r["id"]]["txid"]: r["result"]
for r in results
if r.get("result") is not None
}
except Exception as e:
log.warning("RPC batch unavailable, falling back to single calls: %s", e)
raw_map = {}
for tx in txs:
try:
raw = rpc.getrawtransaction(tx["txid"], False)
if raw:
raw_map[tx["txid"]] = raw
except Exception as e2:
log.debug("Missing raw witness for %s: %s", tx["txid"], e2)
template["transactions"] = [
{"hash": tx["txid"], "data": raw_map.get(tx["txid"], tx["data"])}
for tx in txs
]
def submit_block(rpc, serialized_block: str) -> None:
"""Submit the mined block to the Bitcoin node."""
log.info("Submitting serialized block (%d bytes) to node", len(serialized_block) // 2)
if not serialized_block:
log.error("Block not serialized correctly - submission canceled")
return
try:
result = rpc.submitblock(serialized_block)
if result is None:
log.info("Block accepted into the blockchain")
else:
log.error("submitblock returned: %s", result)
except Exception:
log.exception("RPC error during submitblock")