Files
m2pool_docs/m2pool_backend_app/lib/node.py

298 lines
8.5 KiB
Python
Raw Normal View History

2026-01-30 17:47:21 +08:00
import httpx
class BaseRPCNode:
def __init__(self, NODE_OPTION):
self.rpcUser = NODE_OPTION.get("rpcUser")
self.rpcHost = NODE_OPTION.get("rpcHost")
self.rpcPassword = NODE_OPTION.get("rpcPassword")
self.rpcPort = NODE_OPTION.get("rpcPort")
self.base_url = f"http://{self.rpcHost}:{self.rpcPort}"
self.client = httpx.AsyncClient(
base_url=self.base_url,
auth=(self.rpcUser, self.rpcPassword),
timeout=5.0
)
async def callRpcMethod(self, method, params=None):
if params is None:
params = []
try:
response = await self.client.post("/", json={
"jsonrpc": "1.0",
"id": "testnet",
"method": method,
"params": params
})
response.raise_for_status()
return response.json()["result"]
except httpx.HTTPStatusError as e:
print("RPC Error:", e.response.text)
raise
except Exception as e:
print("RPC Error:", str(e))
raise
async def getblockcount(self):
return await self.callRpcMethod("getblockcount", [])
async def getblockhash(self, height):
return await self.callRpcMethod("getblockhash", [height])
async def getblock(self, param):
if isinstance(param, str):
return await self.callRpcMethod("getblock", [param, 2])
elif isinstance(param, int):
hash_ = await self.getblockhash(param)
return await self.callRpcMethod("getblock", [hash_, 2])
else:
raise ValueError("param must be str or int")
# ================= NEXA =================
class NEXARPCNode(BaseRPCNode):
async def verify_wallet(self, address):
try:
await self.callRpcMethod("getreceivedbyaddress", [address])
return True
except Exception:
return False
async def getblock(self, height):
return await self.callRpcMethod("getblock", [height, 2])
async def verify_block(self, height, address):
block_data = await self.getblock(height)
for item in block_data["tx"]:
if len(item["vin"]) == 0:
addresses = item["vout"][0]["scriptPubKey"]["addresses"]
if address == addresses[0]:
return block_data
else:
return False
def block(self, block_data):
tx = block_data["tx"]
time = block_data["time"]
hash_ = block_data["hash"]
height = block_data["height"]
block_fees = 0
block_reward = 0
for item in tx:
if len(item["vin"]) == 0:
block_reward = item["sends"]
else:
block_fees += item.get("fee", 0)
return {
"height": height,
"hash": hash_,
"time": time,
"block_reward": block_reward,
"block_fees": block_fees
}
# ================= GRS =================
class GRSRPCNode(BaseRPCNode):
async def verify_block(self, height, REPORT_ADDRESS):
block_data = await self.getblock(height)
for item in block_data["tx"]:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
addr = value["scriptPubKey"].get("address")
if addr:
if addr == REPORT_ADDRESS:
return block_data
else:
return False
return False
def block(self, data):
hash_ = data["hash"]
tx = data["tx"]
height = data["height"]
time = data["time"]
reward = 0
fees = 0
for item in tx:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
reward += value["value"]
else:
fees += item.get("fee", 0)
return {
"height": height,
"hash": hash_,
"time": time,
"block_reward": reward,
"block_fees": fees
}
# ================= MONA =================
class MONARPCNode(BaseRPCNode):
async def verify_block(self, height, REPORT_ADDRESS):
block_data = await self.getblock(height)
for item in block_data["tx"]:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
addresses = value["scriptPubKey"].get("addresses")
if addresses:
first = addresses.get("0") if isinstance(addresses, dict) else addresses[0]
if first == REPORT_ADDRESS:
return block_data
else:
return False
return False
def block(self, data):
hash_ = data["hash"]
tx = data["tx"]
height = data["height"]
time = data["time"]
reward = 0
for item in tx:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
if value["scriptPubKey"].get("addresses"):
reward += value["value"]
return {
"height": height,
"hash": hash_,
"time": time,
"block_reward": reward,
"block_fees": None
}
# ================= DGB =================
class DGBRPCNode(BaseRPCNode):
async def verify_block(self, height, REPORT_ADDRESS):
block_data = await self.getblock(height)
for item in block_data["tx"]:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
addresses = value["scriptPubKey"].get("addresses")
if addresses and addresses[0] == REPORT_ADDRESS:
return block_data
return False
async def verify_block_with_algo(self, height, REPORT_ADDRESS, algorithm):
block_data = await self.getblock(height)
if block_data.get("pow_algo") == algorithm:
for item in block_data["tx"]:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
addresses = value["scriptPubKey"].get("addresses")
if addresses and addresses[0] == REPORT_ADDRESS:
return block_data
return False
def block(self, data):
hash_ = data["hash"]
tx = data["tx"]
height = data["height"]
time = data["time"]
reward = 0
for item in tx:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
if value["scriptPubKey"].get("addresses"):
reward += value["value"]
return {
"height": height,
"hash": hash_,
"time": time,
"block_reward": reward,
"block_fees": None
}
# ================= RXD =================
class RXDRPCNode(BaseRPCNode):
async def verify_block(self, height, REPORT_ADDRESS):
block_data = await self.getblock(height)
for item in block_data["tx"]:
vin = item["vin"]
vout = item["vout"]
if vin[0].get("coinbase"):
for value in vout:
addresses = value["scriptPubKey"].get("addresses")
if addresses and addresses[0] == REPORT_ADDRESS:
hash_ = await self.getblockhash(height)
blockstats = await self.callRpcMethod("getblockstats", [hash_])
return {
"height": blockstats["height"],
"hash": blockstats["blockhash"],
"time": blockstats["time"],
"block_reward": blockstats["subsidy"] + blockstats["totalfee"],
"block_fees": blockstats["totalfee"]
}
return False
def block(self, data):
return data
__all__ = [
"NEXARPCNode",
"GRSRPCNode",
"MONARPCNode",
"DGBRPCNode",
"RXDRPCNode"
]