|
@ -43,7 +43,8 @@ from aiohttp import ClientResponse |
|
|
|
|
|
|
|
|
from . import util |
|
|
from . import util |
|
|
from .util import (PrintError, print_error, log_exceptions, ignore_exceptions, |
|
|
from .util import (PrintError, print_error, log_exceptions, ignore_exceptions, |
|
|
bfh, SilentTaskGroup, make_aiohttp_session, send_exception_to_crash_reporter) |
|
|
bfh, SilentTaskGroup, make_aiohttp_session, send_exception_to_crash_reporter, |
|
|
|
|
|
is_hash256_str, is_non_negative_integer) |
|
|
|
|
|
|
|
|
from .bitcoin import COIN |
|
|
from .bitcoin import COIN |
|
|
from . import constants |
|
|
from . import constants |
|
@ -195,6 +196,17 @@ class TxBroadcastUnknownError(TxBroadcastError): |
|
|
_("Consider trying to connect to a different server, or updating Electrum.")) |
|
|
_("Consider trying to connect to a different server, or updating Electrum.")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UntrustedServerReturnedError(Exception): |
|
|
|
|
|
def __init__(self, *, original_exception): |
|
|
|
|
|
self.original_exception = original_exception |
|
|
|
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
|
|
return _("The server returned an error.") |
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
|
|
return f"<UntrustedServerReturnedError original_exception: {repr(self.original_exception)}>" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INSTANCE = None |
|
|
INSTANCE = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -760,8 +772,21 @@ class Network(PrintError): |
|
|
raise BestEffortRequestFailed('no interface to do request on... gave up.') |
|
|
raise BestEffortRequestFailed('no interface to do request on... gave up.') |
|
|
return make_reliable_wrapper |
|
|
return make_reliable_wrapper |
|
|
|
|
|
|
|
|
|
|
|
def catch_server_exceptions(func): |
|
|
|
|
|
async def wrapper(self, *args, **kwargs): |
|
|
|
|
|
try: |
|
|
|
|
|
await func(self, *args, **kwargs) |
|
|
|
|
|
except aiorpcx.jsonrpc.CodeMessageError as e: |
|
|
|
|
|
raise UntrustedServerReturnedError(original_exception=e) |
|
|
|
|
|
return wrapper |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
|
|
|
|
@catch_server_exceptions |
|
|
async def get_merkle_for_transaction(self, tx_hash: str, tx_height: int) -> dict: |
|
|
async def get_merkle_for_transaction(self, tx_hash: str, tx_height: int) -> dict: |
|
|
|
|
|
if not is_hash256_str(tx_hash): |
|
|
|
|
|
raise Exception(f"{repr(tx_hash)} is not a txid") |
|
|
|
|
|
if not is_non_negative_integer(tx_height): |
|
|
|
|
|
raise Exception(f"{repr(tx_height)} is not a block height") |
|
|
return await self.interface.session.send_request('blockchain.transaction.get_merkle', [tx_hash, tx_height]) |
|
|
return await self.interface.session.send_request('blockchain.transaction.get_merkle', [tx_hash, tx_height]) |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
@ -919,24 +944,39 @@ class Network(PrintError): |
|
|
return _("Unknown error") |
|
|
return _("Unknown error") |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
|
async def request_chunk(self, height, tip=None, *, can_return_early=False): |
|
|
@catch_server_exceptions |
|
|
|
|
|
async def request_chunk(self, height: int, tip=None, *, can_return_early=False): |
|
|
|
|
|
if not is_non_negative_integer(height): |
|
|
|
|
|
raise Exception(f"{repr(height)} is not a block height") |
|
|
return await self.interface.request_chunk(height, tip=tip, can_return_early=can_return_early) |
|
|
return await self.interface.request_chunk(height, tip=tip, can_return_early=can_return_early) |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
|
|
|
|
@catch_server_exceptions |
|
|
async def get_transaction(self, tx_hash: str, *, timeout=None) -> str: |
|
|
async def get_transaction(self, tx_hash: str, *, timeout=None) -> str: |
|
|
|
|
|
if not is_hash256_str(tx_hash): |
|
|
|
|
|
raise Exception(f"{repr(tx_hash)} is not a txid") |
|
|
return await self.interface.session.send_request('blockchain.transaction.get', [tx_hash], |
|
|
return await self.interface.session.send_request('blockchain.transaction.get', [tx_hash], |
|
|
timeout=timeout) |
|
|
timeout=timeout) |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
|
|
|
|
@catch_server_exceptions |
|
|
async def get_history_for_scripthash(self, sh: str) -> List[dict]: |
|
|
async def get_history_for_scripthash(self, sh: str) -> List[dict]: |
|
|
|
|
|
if not is_hash256_str(sh): |
|
|
|
|
|
raise Exception(f"{repr(sh)} is not a scripthash") |
|
|
return await self.interface.session.send_request('blockchain.scripthash.get_history', [sh]) |
|
|
return await self.interface.session.send_request('blockchain.scripthash.get_history', [sh]) |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
|
|
|
|
@catch_server_exceptions |
|
|
async def listunspent_for_scripthash(self, sh: str) -> List[dict]: |
|
|
async def listunspent_for_scripthash(self, sh: str) -> List[dict]: |
|
|
|
|
|
if not is_hash256_str(sh): |
|
|
|
|
|
raise Exception(f"{repr(sh)} is not a scripthash") |
|
|
return await self.interface.session.send_request('blockchain.scripthash.listunspent', [sh]) |
|
|
return await self.interface.session.send_request('blockchain.scripthash.listunspent', [sh]) |
|
|
|
|
|
|
|
|
@best_effort_reliable |
|
|
@best_effort_reliable |
|
|
|
|
|
@catch_server_exceptions |
|
|
async def get_balance_for_scripthash(self, sh: str) -> dict: |
|
|
async def get_balance_for_scripthash(self, sh: str) -> dict: |
|
|
|
|
|
if not is_hash256_str(sh): |
|
|
|
|
|
raise Exception(f"{repr(sh)} is not a scripthash") |
|
|
return await self.interface.session.send_request('blockchain.scripthash.get_balance', [sh]) |
|
|
return await self.interface.session.send_request('blockchain.scripthash.get_balance', [sh]) |
|
|
|
|
|
|
|
|
def blockchain(self) -> Blockchain: |
|
|
def blockchain(self) -> Blockchain: |
|
|