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

+1 -238
View File
@@ -11,18 +11,13 @@ daemon.'''
import asyncio
import itertools
import time
from calendar import timegm
from struct import pack
from typing import TYPE_CHECKING, Type, Sequence, Any, Iterable, Optional
import aiohttp
from aiorpcx import JSONRPC
from electrumx.lib.hash import hash_to_hex_str, hex_str_to_hash
from electrumx.lib.tx import DeserializerDecred
from electrumx.lib.util import (class_logger, hex_to_bytes, json_deserialize,
json_serialize, pack_varint,
unpack_le_uint16_from)
json_serialize)
if TYPE_CHECKING:
from electrumx.lib.coins import Coin
@@ -404,235 +399,3 @@ class Daemon:
If the daemon has not been queried yet this returns None.'''
return self._height
class DashDaemon(Daemon):
async def masternode_broadcast(self, params):
'''Broadcast a transaction to the network.'''
return await self._send_single('masternodebroadcast', params)
async def masternode_list(self, params):
'''Return the masternode status.'''
return await self._send_single('masternodelist', params)
async def protx(self, params):
'''Set of commands to execute ProTx related actions.'''
return await self._send_single('protx', params)
class FakeEstimateFeeDaemon(Daemon):
'''Daemon that simulates estimatefee and relayfee RPC calls. Coin that
wants to use this daemon must define ESTIMATE_FEE & RELAY_FEE'''
async def estimatefee(self, block_count):
'''Return the fee estimate for the given parameters.'''
return self.coin.ESTIMATE_FEE
async def relayfee(self):
"""The minimum fee required for a transaction to be relayed on by the server to the
bitcoin network. Doesn't guarantee mempool acceptance."""
return self.coin.RELAY_FEE
class LegacyRPCDaemon(Daemon):
'''Handles connections to a daemon at the given URL.
This class is useful for daemons that don't have the new 'getblock'
RPC call that returns the block in hex, the workaround is to manually
recreate the block bytes. The recreated block bytes may not be the exact
as in the underlying blockchain but it is good enough for our indexing
purposes.'''
async def raw_blocks(self, bhashes_hum):
'''Return the raw binary blocks with the given hex hashes.'''
params_iterable = ((h, ) for h in bhashes_hum)
block_info = await self._send_vector('getblock', params_iterable)
blocks = []
for i in block_info:
raw_block = await self.make_raw_block(i)
blocks.append(raw_block)
# Convert hex string to bytes
return blocks
async def make_raw_header(self, b):
pbh = b.get('previousblockhash')
if pbh is None:
pbh = '0' * 64
return b''.join([
pack('<L', b.get('version')),
hex_str_to_hash(pbh),
hex_str_to_hash(b.get('merkleroot')),
pack('<L', self.timestamp_safe(b['time'])),
pack('<L', int(b.get('bits'), 16)),
pack('<L', int(b.get('nonce')))
])
async def make_raw_block(self, b):
'''Construct a raw block'''
header = await self.make_raw_header(b)
transactions = []
if b.get('height') > 0:
transactions = await self.getrawtransactions(b.get('tx'), False)
raw_block = header
num_txs = len(transactions)
if num_txs > 0:
raw_block += pack_varint(num_txs)
raw_block += b''.join(transactions)
else:
raw_block += b'\x00'
return raw_block
def timestamp_safe(self, t):
if isinstance(t, int):
return t
return timegm(time.strptime(t, "%Y-%m-%d %H:%M:%S %Z"))
class FakeEstimateLegacyRPCDaemon(LegacyRPCDaemon, FakeEstimateFeeDaemon):
pass
class DecredDaemon(Daemon):
async def raw_blocks(self, bhashes_hum):
'''Return the raw binary blocks with the given hex hashes.'''
params_iterable = ((h, False) for h in bhashes_hum)
blocks = await self._send_vector('getblock', params_iterable)
raw_blocks = []
valid_tx_tree = {}
for block in blocks:
# Convert to bytes from hex
raw_block = hex_to_bytes(block)
raw_blocks.append(raw_block)
# Check if previous block is valid
prev = self.prev_hex_hash(raw_block)
votebits = unpack_le_uint16_from(raw_block[100:102])[0]
valid_tx_tree[prev] = self.is_valid_tx_tree(votebits)
processed_raw_blocks = []
for hash, raw_block in zip(bhashes_hum, raw_blocks):
if hash in valid_tx_tree:
is_valid = valid_tx_tree[hash]
else:
# Do something complicated to figure out if this block is valid
header = await self._send_single('getblockheader', (hash, ))
if 'nextblockhash' not in header:
raise DaemonError(f'Could not find next block for {hash}')
next_hash = header['nextblockhash']
next_header = await self._send_single('getblockheader',
(next_hash, ))
is_valid = self.is_valid_tx_tree(next_header['votebits'])
if is_valid:
processed_raw_blocks.append(raw_block)
else:
# If this block is invalid remove the normal transactions
self.logger.info(f'block {hash} is invalidated')
processed_raw_blocks.append(self.strip_tx_tree(raw_block))
return processed_raw_blocks
@staticmethod
def prev_hex_hash(raw_block):
return hash_to_hex_str(raw_block[4:36])
@staticmethod
def is_valid_tx_tree(votebits):
# Check if previous block was invalidated.
return bool(votebits & (1 << 0) != 0)
def strip_tx_tree(self, raw_block):
c = self.coin
assert issubclass(c.DESERIALIZER, DeserializerDecred)
d = c.DESERIALIZER(raw_block, start=c.BASIC_HEADER_SIZE)
d.read_tx_tree() # Skip normal transactions
# Create a fake block without any normal transactions
return raw_block[:c.BASIC_HEADER_SIZE] + b'\x00' + raw_block[d.cursor:]
async def height(self):
height = await super().height()
if height > 0:
# Lie about the daemon height as the current tip can be invalidated
height -= 1
self._height = height
return height
async def mempool_txids_hum(self):
mempool = await super().mempool_txids_hum()
# Add current tip transactions to the 'fake' mempool.
real_height = await self._send_single('getblockcount')
tip_hash = await self._send_single('getblockhash', (real_height,))
tip = await self.deserialised_block(tip_hash)
# Add normal transactions except coinbase
mempool += tip['tx'][1:]
# Add stake transactions if applicable
mempool += tip.get('stx', [])
return mempool
def connector(self):
# FIXME allow self signed certificates
return aiohttp.TCPConnector(verify_ssl=False)
class PreLegacyRPCDaemon(LegacyRPCDaemon):
'''Handles connections to a daemon at the given URL.
This class is useful for daemons that don't have the new 'getblock'
RPC call that returns the block in hex, and need the False parameter
for the getblock'''
async def deserialised_block(self, hex_hash):
'''Return the deserialised block with the given hex hash.'''
return await self._send_single('getblock', (hex_hash, False))
class SmartCashDaemon(Daemon):
async def masternode_broadcast(self, params):
'''Broadcast a smartnode to the network.'''
return await self._send_single('smartnodebroadcast', params)
async def masternode_list(self, params):
'''Return the smartnode status.'''
return await self._send_single('smartnodelist', params)
async def smartrewards(self, params):
'''Return smartrewards data.'''
return await self._send_single('smartrewards', params)
class ZcoinMtpDaemon(Daemon):
def strip_mtp_data(self, raw_block):
if self.coin.is_mtp(raw_block):
return \
raw_block[:self.coin.MTP_HEADER_DATA_START*2] + \
raw_block[self.coin.MTP_HEADER_DATA_END*2:]
return raw_block
async def raw_blocks(self, bhashes_hum):
'''Return the raw binary blocks with the given hex hashes.'''
params_iterable = ((h, False) for h in bhashes_hum)
blocks = await self._send_vector('getblock', params_iterable)
# Convert hex string to bytes
return [hex_to_bytes(self.strip_mtp_data(block)) for block in blocks]
async def masternode_broadcast(self, params):
'''Broadcast a transaction to the network.'''
return await self._send_single('znodebroadcast', params)
async def masternode_list(self, params):
'''Return the masternode status.'''
return await self._send_single('znodelist', params)
async def protx(self, params):
'''Set of commands to execute ProTx related actions.'''
return await self._send_single('protx', params)