Remove altcoin-only server and tx code

Deletes the transaction deserializers of other coins (tx.py keeps only the
Bitcoin/segwit ones), tx_dash.py, tx_axe.py, and the session, daemon and block
processor subclasses that only other coins used.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-10-22 15:03:56 +02:00
1 parent 73c96101bd
commit 05f5fc9058
6 files changed
+3 -2745

No files matched your search

-333
View File
@@ -10,7 +10,6 @@
import asyncio
import codecs
from dataclasses import dataclass
import datetime
import itertools
import math
import os
@@ -2439,335 +2438,3 @@ class LocalRPC(SessionBase):
def protocol_version_string(self):
return 'RPC'
######################################################################
# Non-Bitcoin stuff goes strictly below this line.
######################################################################
class DashElectrumX(ElectrumX):
'''A TCP server that handles incoming Electrum Dash connections.'''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.mns = set()
self.mn_cache_height = 0
self.mn_cache = []
def set_request_handlers(self, ptuple):
super().set_request_handlers(ptuple)
self.request_handlers.update({
'masternode.announce.broadcast': self.phandle_masternode_announce_broadcast,
'masternode.subscribe': self.phandle_masternode_subscribe,
'masternode.list': self.phandle_masternode_list,
'protx.diff': self.phandle_protx_diff,
'protx.info': self.phandle_protx_info,
})
async def _notify_inner(
self,
*,
touched_hashxs,
touched_outpoints,
height_changed,
):
'''Notify the client about changes in masternode list.'''
await super()._notify_inner(
touched_hashxs=touched_hashxs,
touched_outpoints=touched_outpoints,
height_changed=height_changed,
)
for mn in self.mns.copy():
status = await self.daemon_request('masternode_list',
('status', mn))
await self.send_notification('masternode.subscribe',
(mn, status.get(mn)))
# Masternode command handlers
async def phandle_masternode_announce_broadcast(self, signmnb):
'''Pass through the masternode announce message to be broadcast
by the daemon.
signmnb: signed masternode broadcast message.'''
try:
return await self.daemon_request('masternode_broadcast',
('relay', signmnb))
except DaemonError as e:
error, = e.args
message = error['message']
self.logger.info(f'masternode_broadcast: {message}')
raise RPCError(BAD_REQUEST, 'the masternode broadcast was '
f'rejected.\n\n{message}\n[{signmnb}]')
async def phandle_masternode_subscribe(self, collateral):
'''Returns the status of masternode.
collateral: masternode collateral.
'''
result = await self.daemon_request('masternode_list',
('status', collateral))
if result is not None:
self.mns.add(collateral)
return result.get(collateral)
return None
async def phandle_masternode_list(self, payees):
'''
Returns the list of masternodes.
payees: a list of masternode payee addresses.
'''
if not isinstance(payees, list):
raise RPCError(BAD_REQUEST, 'expected a list of payees')
def get_masternode_payment_queue(mns):
'''Returns the calculated position in the payment queue for all the
valid masterernodes in the given mns list.
mns: a list of masternodes information.
'''
now = int(datetime.datetime.utcnow().strftime("%s"))
mn_queue = []
# Only ENABLED masternodes are considered for the list.
for line in mns:
mnstat = mns[line].split()
if mnstat[0] == 'ENABLED':
# if last paid time == 0
if int(mnstat[5]) == 0:
# use active seconds
mnstat.append(int(mnstat[4]))
else:
# now minus last paid
delta = now - int(mnstat[5])
# if > active seconds, use active seconds
if delta >= int(mnstat[4]):
mnstat.append(int(mnstat[4]))
# use active seconds
else:
mnstat.append(delta)
mn_queue.append(mnstat)
mn_queue = sorted(mn_queue, key=lambda x: x[8], reverse=True)
return mn_queue
def get_payment_position(payment_queue, address):
'''
Returns the position of the payment list for the given address.
payment_queue: position in the payment queue for the masternode.
address: masternode payee address.
'''
position = -1
for pos, mn in enumerate(payment_queue, start=1):
if mn[2] == address:
position = pos
break
return position
# Accordingly with the masternode payment queue, a custom list
# with the masternode information including the payment
# position is returned.
cache = self.session_mgr.mn_cache
if not cache or self.session_mgr.mn_cache_height != self.db.db_height:
full_mn_list = await self.daemon_request('masternode_list',
('full',))
mn_payment_queue = get_masternode_payment_queue(full_mn_list)
mn_payment_count = len(mn_payment_queue)
mn_list = []
for key, value in full_mn_list.items():
mn_data = value.split()
mn_info = {
'vin': key,
'status': mn_data[0],
'protocol': mn_data[1],
'payee': mn_data[2],
'lastseen': mn_data[3],
'activeseconds': mn_data[4],
'lastpaidtime': mn_data[5],
'lastpaidblock': mn_data[6],
'ip': mn_data[7]
}
mn_info['paymentposition'] = get_payment_position(
mn_payment_queue, mn_info['payee']
)
mn_info['inselection'] = (
mn_info['paymentposition'] < mn_payment_count // 10
)
hashX = self.coin.address_to_hashX(mn_info['payee'])
balance = await self.get_balance(hashX)
mn_info['balance'] = (sum(balance.values())
/ self.coin.VALUE_PER_COIN)
mn_list.append(mn_info)
cache.clear()
cache.extend(mn_list)
self.session_mgr.mn_cache_height = self.db.db_height
# If payees is an empty list the whole masternode list is returned
if payees:
return [mn for mn in cache if mn['payee'] in payees]
else:
return cache
async def phandle_protx_diff(self, base_height, height):
'''
Calculates a diff between two deterministic masternode lists.
The result also contains proof data.
base_height: The starting block height (starting from 1).
height: The ending block height.
'''
if not isinstance(base_height, int) or not isinstance(height, int):
raise RPCError(BAD_REQUEST, 'expected a int block heights')
max_height = self.db.db_height
if (not 1 <= base_height <= max_height or
not base_height <= height <= max_height):
raise RPCError(BAD_REQUEST,
f'require 1 <= base_height {base_height:,d} <= '
f'height {height:,d} <= '
f'chain height {max_height:,d}')
return await self.daemon_request('protx',
('diff', base_height, height))
async def phandle_protx_info(self, protx_hash):
'''
Returns detailed information about a deterministic masternode.
protx_hash: The hash of the initial ProRegTx
'''
if not isinstance(protx_hash, str):
raise RPCError(BAD_REQUEST, 'expected protx hash string')
res = await self.daemon_request('protx', ('info', protx_hash))
if 'wallet' in res:
del res['wallet']
return res
class SmartCashElectrumX(DashElectrumX):
'''A TCP server that handles incoming Electrum-SMART connections.'''
def set_request_handlers(self, ptuple):
super().set_request_handlers(ptuple)
self.request_handlers.update({
'smartrewards.current': self.phandle_smartrewards_current,
'smartrewards.check': self.phandle_smartrewards_check
})
async def phandle_smartrewards_current(self):
'''Returns the current smartrewards info.'''
result = await self.daemon_request('smartrewards', ('current',))
if result is not None:
return result
return None
async def phandle_smartrewards_check(self, addr):
'''
Returns the status of an address
addr: a single smartcash address
'''
result = await self.daemon_request('smartrewards', ('check', addr))
if result is not None:
return result
return None
class AuxPoWElectrumX(ElectrumX):
async def phandle_block_header(self, height, cp_height=0):
result = await super().phandle_block_header(height, cp_height)
# Older protocol versions don't truncate AuxPoW
if self.protocol_tuple < (1, 4, 1):
return result
# Not covered by a checkpoint; return full AuxPoW data
if cp_height == 0:
return result
# Covered by a checkpoint; truncate AuxPoW data
result['header'] = self.truncate_auxpow_single(result['header'])
return result
async def phandle_block_headers(self, start_height, count, cp_height=0):
# Older protocol versions don't truncate AuxPoW
if self.protocol_tuple < (1, 4, 1):
return await super().phandle_block_headers(start_height, count, cp_height)
# Not covered by a checkpoint; return full AuxPoW data
if cp_height == 0:
return await super().phandle_block_headers(start_height, count, cp_height)
result = await super().block_headers_array(start_height, count, cp_height)
# Covered by a checkpoint; truncate AuxPoW data
result['headers'] = self.truncate_auxpow_headers(result['headers'])
# Return headers in array form
if self.protocol_tuple >= (1, 6):
return result
# Return headers in concatenated form
result['hex'] = ''.join(result['headers'])
del result['headers']
return result
def truncate_auxpow_headers(self, headers):
result = []
for header in headers:
result.append(self.truncate_auxpow_single(header))
return result
def truncate_auxpow_single(self, header: str):
# 2 hex chars per byte
return header[:2*self.coin.TRUNCATED_HEADER_SIZE]
class NameIndexElectrumX(ElectrumX):
def set_request_handlers(self, ptuple):
super().set_request_handlers(ptuple)
if ptuple >= (1, 4, 3):
self.request_handlers['blockchain.name.get_value_proof'] = self.phandle_name_get_value_proof
async def phandle_name_get_value_proof(self, scripthash, cp_height=0):
history = await self.phandle_scripthash_get_history(scripthash)
trimmed_history = []
prev_height = None
for update in history[::-1]:
txid = update['tx_hash']
height = update['height']
if (self.coin.NAME_EXPIRATION is not None
and prev_height is not None
and height < prev_height - self.coin.NAME_EXPIRATION):
break
tx = await self.phandle_transaction_get(txid)
update['tx'] = tx
del update['tx_hash']
tx_merkle = await self.phandle_transaction_merkle(txid, height)
del tx_merkle['block_height']
update['tx_merkle'] = tx_merkle
if height <= cp_height:
header = await self.phandle_block_header(height, cp_height)
update['header'] = header
trimmed_history.append(update)
if height <= cp_height:
break
prev_height = height
return {scripthash: trimmed_history}
class NameIndexAuxPoWElectrumX(NameIndexElectrumX, AuxPoWElectrumX):
pass