mirror of
https://github.com/basicswap/basicswap.git
synced 2024-11-16 15:58:17 +00:00
wownero: deduplicate
This commit is contained in:
parent
ee2f462ee9
commit
dc4f0ac2d3
8 changed files with 23 additions and 844 deletions
|
@ -34,7 +34,6 @@ from .interface.part import PARTInterface, PARTInterfaceAnon, PARTInterfaceBlind
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .rpc import escape_rpcauth
|
from .rpc import escape_rpcauth
|
||||||
from .rpc_xmr import make_xmr_rpc2_func
|
from .rpc_xmr import make_xmr_rpc2_func
|
||||||
from .rpc_wow import make_wow_rpc2_func
|
|
||||||
from .ui.util import getCoinName, known_chart_coins
|
from .ui.util import getCoinName, known_chart_coins
|
||||||
from .util import (
|
from .util import (
|
||||||
AutomationConstraint,
|
AutomationConstraint,
|
||||||
|
@ -601,10 +600,8 @@ class BasicSwap(BaseApp):
|
||||||
if proxy_host:
|
if proxy_host:
|
||||||
self.log.info(f'Connecting through proxy at {proxy_host}.')
|
self.log.info(f'Connecting through proxy at {proxy_host}.')
|
||||||
|
|
||||||
if coin == Coins.XMR:
|
if coin in (Coins.XMR, Coins.WOW):
|
||||||
return make_xmr_rpc2_func(rpcport, daemon_login, rpchost, proxy_host=proxy_host, proxy_port=proxy_port)
|
return make_xmr_rpc2_func(rpcport, daemon_login, rpchost, proxy_host=proxy_host, proxy_port=proxy_port)
|
||||||
if coin == Coins.WOW:
|
|
||||||
return make_wow_rpc2_func(rpcport, daemon_login, rpchost, proxy_host=proxy_host, proxy_port=proxy_port)
|
|
||||||
|
|
||||||
daemon_login = None
|
daemon_login = None
|
||||||
if coin_settings.get('rpcuser', '') != '':
|
if coin_settings.get('rpcuser', '') != '':
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Coins(IntEnum):
|
||||||
FIRO = 13
|
FIRO = 13
|
||||||
NAV = 14
|
NAV = 14
|
||||||
LTC_MWEB = 15
|
LTC_MWEB = 15
|
||||||
# ZANO = 16 was 9
|
# ZANO = 16
|
||||||
|
|
||||||
|
|
||||||
chainparams = {
|
chainparams = {
|
||||||
|
|
|
@ -295,7 +295,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
cmd = get_data_entry(form_data, 'cmd')
|
cmd = get_data_entry(form_data, 'cmd')
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError('Invalid command')
|
raise ValueError('Invalid command')
|
||||||
if coin_type in (Coins.XMR, ):
|
if coin_type in (Coins.XMR, Coins.WOW):
|
||||||
ci = swap_client.ci(coin_type)
|
ci = swap_client.ci(coin_type)
|
||||||
arr = cmd.split(None, 1)
|
arr = cmd.split(None, 1)
|
||||||
method = arr[0]
|
method = arr[0]
|
||||||
|
@ -311,22 +311,6 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown RPC variant')
|
raise ValueError('Unknown RPC variant')
|
||||||
result = json.dumps(rv, indent=4)
|
result = json.dumps(rv, indent=4)
|
||||||
elif coin_type == Coins.WOW:
|
|
||||||
ci = swap_client.ci(coin_type)
|
|
||||||
arr = cmd.split(None, 1)
|
|
||||||
method = arr[0]
|
|
||||||
params = json.loads(arr[1]) if len(arr) > 1 else []
|
|
||||||
if coin_id == -8:
|
|
||||||
rv = ci.rpc_wallet(method, params)
|
|
||||||
elif coin_id == -7:
|
|
||||||
rv = ci.rpc(method, params)
|
|
||||||
elif coin_id == -6:
|
|
||||||
if params == []:
|
|
||||||
params = None
|
|
||||||
rv = ci.rpc2(method, params)
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown WOW RPC variant')
|
|
||||||
result = json.dumps(rv, indent=4)
|
|
||||||
else:
|
else:
|
||||||
if call_type == 'http':
|
if call_type == 'http':
|
||||||
ci = swap_client.ci(coin_type)
|
ci = swap_client.ci(coin_type)
|
||||||
|
|
|
@ -1,54 +1,23 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2020-2024 tecnovert
|
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
import json
|
from basicswap.chainparams import WOW_COIN, Coins
|
||||||
import logging
|
from .xmr import XMRInterface
|
||||||
|
|
||||||
import basicswap.contrib.ed25519_fast as edf
|
|
||||||
import basicswap.ed25519_fast_util as edu
|
|
||||||
import basicswap.util_xmr as wow_util
|
|
||||||
from coincurve.ed25519 import (
|
|
||||||
ed25519_add,
|
|
||||||
ed25519_get_pubkey,
|
|
||||||
ed25519_scalar_add,
|
|
||||||
)
|
|
||||||
from coincurve.keys import PrivateKey
|
|
||||||
from coincurve.dleag import (
|
|
||||||
dleag_prove,
|
|
||||||
dleag_verify,
|
|
||||||
dleag_proof_len,
|
|
||||||
verify_ed25519_point,
|
|
||||||
)
|
|
||||||
|
|
||||||
from basicswap.interface import (
|
|
||||||
Curves)
|
|
||||||
from basicswap.util import (
|
|
||||||
i2b, b2i, b2h,
|
|
||||||
dumpj,
|
|
||||||
ensure,
|
|
||||||
make_int,
|
|
||||||
TemporaryError)
|
|
||||||
from basicswap.util.network import (
|
|
||||||
is_private_ip_address)
|
|
||||||
from basicswap.rpc_wow import (
|
|
||||||
make_wow_rpc_func,
|
|
||||||
make_wow_rpc2_func)
|
|
||||||
from basicswap.chainparams import WOW_COIN, CoinInterface, Coins
|
|
||||||
|
|
||||||
|
|
||||||
class WOWInterface(CoinInterface):
|
class WOWInterface(XMRInterface):
|
||||||
@staticmethod
|
|
||||||
def curve_type():
|
|
||||||
return Curves.ed25519
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.WOW
|
return Coins.WOW
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ticker_str() -> int:
|
||||||
|
return Coins.WOW.name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def COIN():
|
def COIN():
|
||||||
return WOW_COIN
|
return WOW_COIN
|
||||||
|
@ -56,522 +25,3 @@ class WOWInterface(CoinInterface):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exp() -> int:
|
def exp() -> int:
|
||||||
return 11
|
return 11
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def nbk() -> int:
|
|
||||||
return 32
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def nbK() -> int: # No. of bytes requires to encode a public key
|
|
||||||
return 32
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def depth_spendable() -> int:
|
|
||||||
return 10
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def xmr_swap_a_lock_spend_tx_vsize() -> int:
|
|
||||||
raise ValueError('Not possible')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def xmr_swap_b_lock_spend_tx_vsize() -> int:
|
|
||||||
# TODO: Estimate with ringsize
|
|
||||||
return 1604
|
|
||||||
|
|
||||||
def __init__(self, coin_settings, network, swap_client=None):
|
|
||||||
super().__init__(network)
|
|
||||||
|
|
||||||
self._addr_prefix = self.chainparams_network()['address_prefix']
|
|
||||||
|
|
||||||
self.blocks_confirmed = coin_settings['blocks_confirmed']
|
|
||||||
self._restore_height = coin_settings.get('restore_height', 0)
|
|
||||||
self.setFeePriority(coin_settings.get('fee_priority', 0))
|
|
||||||
self._sc = swap_client
|
|
||||||
self._log = self._sc.log if self._sc and self._sc.log else logging
|
|
||||||
self._wallet_password = None
|
|
||||||
self._have_checked_seed = False
|
|
||||||
|
|
||||||
daemon_login = None
|
|
||||||
if coin_settings.get('rpcuser', '') != '':
|
|
||||||
daemon_login = (coin_settings.get('rpcuser', ''), coin_settings.get('rpcpassword', ''))
|
|
||||||
|
|
||||||
rpchost = coin_settings.get('rpchost', '127.0.0.1')
|
|
||||||
proxy_host = None
|
|
||||||
proxy_port = None
|
|
||||||
# Connect to the daemon over a proxy if not running locally
|
|
||||||
if swap_client:
|
|
||||||
chain_client_settings = swap_client.getChainClientSettings(self.coin_type())
|
|
||||||
manage_daemon: bool = chain_client_settings['manage_daemon']
|
|
||||||
if swap_client.use_tor_proxy:
|
|
||||||
if manage_daemon is False:
|
|
||||||
log_str: str = ''
|
|
||||||
have_cc_tor_opt = 'use_tor' in chain_client_settings
|
|
||||||
if have_cc_tor_opt and chain_client_settings['use_tor'] is False:
|
|
||||||
log_str = ' bypassing proxy (use_tor false for WOW)'
|
|
||||||
elif have_cc_tor_opt is False and is_private_ip_address(rpchost):
|
|
||||||
log_str = ' bypassing proxy (private ip address)'
|
|
||||||
else:
|
|
||||||
proxy_host = swap_client.tor_proxy_host
|
|
||||||
proxy_port = swap_client.tor_proxy_port
|
|
||||||
log_str = f' through proxy at {proxy_host}'
|
|
||||||
self._log.info(f'Connecting to remote {self.coin_name()} daemon at {rpchost}{log_str}.')
|
|
||||||
else:
|
|
||||||
self._log.info(f'Not connecting to local {self.coin_name()} daemon through proxy.')
|
|
||||||
elif manage_daemon is False:
|
|
||||||
self._log.info(f'Connecting to remote {self.coin_name()} daemon at {rpchost}.')
|
|
||||||
|
|
||||||
self._rpctimeout = coin_settings.get('rpctimeout', 60)
|
|
||||||
self._walletrpctimeout = coin_settings.get('walletrpctimeout', 120)
|
|
||||||
self._walletrpctimeoutlong = coin_settings.get('walletrpctimeoutlong', 600)
|
|
||||||
|
|
||||||
self.rpc = make_wow_rpc_func(coin_settings['rpcport'], daemon_login, host=rpchost, proxy_host=proxy_host, proxy_port=proxy_port, default_timeout=self._rpctimeout, tag='Node(j) ')
|
|
||||||
self.rpc2 = make_wow_rpc2_func(coin_settings['rpcport'], daemon_login, host=rpchost, proxy_host=proxy_host, proxy_port=proxy_port, default_timeout=self._rpctimeout, tag='Node ') # non-json endpoint
|
|
||||||
self.rpc_wallet = make_wow_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'], host=coin_settings.get('walletrpchost', '127.0.0.1'), default_timeout=self._walletrpctimeout, tag='Wallet ')
|
|
||||||
|
|
||||||
def checkWallets(self) -> int:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def setFeePriority(self, new_priority):
|
|
||||||
ensure(new_priority >= 0 and new_priority < 4, 'Invalid fee_priority value')
|
|
||||||
self._fee_priority = new_priority
|
|
||||||
|
|
||||||
def setWalletFilename(self, wallet_filename):
|
|
||||||
self._wallet_filename = wallet_filename
|
|
||||||
|
|
||||||
def createWallet(self, params):
|
|
||||||
if self._wallet_password is not None:
|
|
||||||
params['password'] = self._wallet_password
|
|
||||||
rv = self.rpc_wallet('generate_from_keys', params)
|
|
||||||
self._log.info('generate_from_keys %s', dumpj(rv))
|
|
||||||
|
|
||||||
def openWallet(self, filename):
|
|
||||||
params = {'filename': filename}
|
|
||||||
if self._wallet_password is not None:
|
|
||||||
params['password'] = self._wallet_password
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Can't reopen the same wallet in windows, !is_keys_file_locked()
|
|
||||||
self.rpc_wallet('close_wallet')
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
self.rpc_wallet('open_wallet', params)
|
|
||||||
|
|
||||||
def initialiseWallet(self, key_view, key_spend, restore_height=None):
|
|
||||||
with self._mx_wallet:
|
|
||||||
try:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
# TODO: Check address
|
|
||||||
return # Wallet exists
|
|
||||||
except Exception as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
Kbv = self.getPubkey(key_view)
|
|
||||||
Kbs = self.getPubkey(key_spend)
|
|
||||||
address_b58 = wow_util.encode_address(Kbv, Kbs, self._addr_prefix)
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'filename': self._wallet_filename,
|
|
||||||
'address': address_b58,
|
|
||||||
'viewkey': b2h(key_view[::-1]),
|
|
||||||
'spendkey': b2h(key_spend[::-1]),
|
|
||||||
'restore_height': self._restore_height,
|
|
||||||
}
|
|
||||||
self.createWallet(params)
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
|
|
||||||
def ensureWalletExists(self) -> None:
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
|
|
||||||
def testDaemonRPC(self, with_wallet=True) -> None:
|
|
||||||
self.rpc_wallet('get_languages')
|
|
||||||
|
|
||||||
def getDaemonVersion(self):
|
|
||||||
return self.rpc_wallet('get_version')['version']
|
|
||||||
|
|
||||||
def getBlockchainInfo(self):
|
|
||||||
get_height = self.rpc2('get_height', timeout=self._rpctimeout)
|
|
||||||
rv = {
|
|
||||||
'blocks': get_height['height'],
|
|
||||||
'verificationprogress': 0.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
# get_block_count.block_count is how many blocks are in the longest chain known to the node.
|
|
||||||
# get_block_count returns "Internal error" if bootstrap-daemon is active
|
|
||||||
if get_height['untrusted'] is True:
|
|
||||||
rv['bootstrapping'] = True
|
|
||||||
get_info = self.rpc2('get_info', timeout=self._rpctimeout)
|
|
||||||
if 'height_without_bootstrap' in get_info:
|
|
||||||
rv['blocks'] = get_info['height_without_bootstrap']
|
|
||||||
|
|
||||||
rv['known_block_count'] = get_info['height']
|
|
||||||
if rv['known_block_count'] > rv['blocks']:
|
|
||||||
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
|
||||||
else:
|
|
||||||
rv['known_block_count'] = self.rpc('get_block_count', timeout=self._rpctimeout)['count']
|
|
||||||
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
|
||||||
except Exception as e:
|
|
||||||
self._log.warning('WOW get_block_count failed with: %s', str(e))
|
|
||||||
rv['verificationprogress'] = 0.0
|
|
||||||
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def getChainHeight(self):
|
|
||||||
return self.rpc2('get_height', timeout=self._rpctimeout)['height']
|
|
||||||
|
|
||||||
def getWalletInfo(self):
|
|
||||||
with self._mx_wallet:
|
|
||||||
try:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
except Exception as e:
|
|
||||||
if 'Failed to open wallet' in str(e):
|
|
||||||
rv = {'encrypted': True, 'locked': True, 'balance': 0, 'unconfirmed_balance': 0}
|
|
||||||
return rv
|
|
||||||
raise e
|
|
||||||
|
|
||||||
rv = {}
|
|
||||||
self.rpc_wallet('refresh')
|
|
||||||
balance_info = self.rpc_wallet('get_balance')
|
|
||||||
|
|
||||||
rv['balance'] = self.format_amount(balance_info['unlocked_balance'])
|
|
||||||
rv['unconfirmed_balance'] = self.format_amount(balance_info['balance'] - balance_info['unlocked_balance'])
|
|
||||||
rv['encrypted'] = False if self._wallet_password is None else True
|
|
||||||
rv['locked'] = False
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def walletRestoreHeight(self):
|
|
||||||
return self._restore_height
|
|
||||||
|
|
||||||
def getMainWalletAddress(self) -> str:
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
return self.rpc_wallet('get_address')['address']
|
|
||||||
|
|
||||||
def getNewAddress(self, placeholder) -> str:
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
new_address = self.rpc_wallet('create_address', {'account_index': 0})['address']
|
|
||||||
self.rpc_wallet('store')
|
|
||||||
return new_address
|
|
||||||
|
|
||||||
def get_fee_rate(self, conf_target: int = 2):
|
|
||||||
# fees - array of unsigned int; Represents the base fees at different priorities [slow, normal, fast, fastest].
|
|
||||||
fee_est = self.rpc('get_fee_estimate')
|
|
||||||
if conf_target <= 1:
|
|
||||||
conf_target = 1 # normal
|
|
||||||
else:
|
|
||||||
conf_target = 0 # slow
|
|
||||||
fee_per_k_bytes = fee_est['fees'][conf_target] * 1000
|
|
||||||
|
|
||||||
return float(self.format_amount(fee_per_k_bytes)), 'get_fee_estimate'
|
|
||||||
|
|
||||||
def getNewSecretKey(self) -> bytes:
|
|
||||||
# Note: Returned bytes are in big endian order
|
|
||||||
return i2b(edu.get_secret())
|
|
||||||
|
|
||||||
def pubkey(self, key: bytes) -> bytes:
|
|
||||||
return edf.scalarmult_B(key)
|
|
||||||
|
|
||||||
def encodeKey(self, vk: bytes) -> str:
|
|
||||||
return vk[::-1].hex()
|
|
||||||
|
|
||||||
def decodeKey(self, k_hex: str) -> bytes:
|
|
||||||
return bytes.fromhex(k_hex)[::-1]
|
|
||||||
|
|
||||||
def encodePubkey(self, pk: bytes) -> str:
|
|
||||||
return edu.encodepoint(pk)
|
|
||||||
|
|
||||||
def decodePubkey(self, pke):
|
|
||||||
return edf.decodepoint(pke)
|
|
||||||
|
|
||||||
def getPubkey(self, privkey):
|
|
||||||
return ed25519_get_pubkey(privkey)
|
|
||||||
|
|
||||||
def getAddressFromKeys(self, key_view: bytes, key_spend: bytes) -> str:
|
|
||||||
pk_view = self.getPubkey(key_view)
|
|
||||||
pk_spend = self.getPubkey(key_spend)
|
|
||||||
return wow_util.encode_address(pk_view, pk_spend, self._addr_prefix)
|
|
||||||
|
|
||||||
def verifyKey(self, k: int) -> bool:
|
|
||||||
i = b2i(k)
|
|
||||||
return (i < edf.l and i > 8)
|
|
||||||
|
|
||||||
def verifyPubkey(self, pubkey_bytes):
|
|
||||||
# Calls ed25519_decode_check_point() in secp256k1
|
|
||||||
# Checks for small order
|
|
||||||
return verify_ed25519_point(pubkey_bytes)
|
|
||||||
|
|
||||||
def proveDLEAG(self, key: bytes) -> bytes:
|
|
||||||
privkey = PrivateKey(key)
|
|
||||||
return dleag_prove(privkey)
|
|
||||||
|
|
||||||
def verifyDLEAG(self, dleag_bytes: bytes) -> bool:
|
|
||||||
return dleag_verify(dleag_bytes)
|
|
||||||
|
|
||||||
def lengthDLEAG(self) -> int:
|
|
||||||
return dleag_proof_len()
|
|
||||||
|
|
||||||
def sumKeys(self, ka: bytes, kb: bytes) -> bytes:
|
|
||||||
return ed25519_scalar_add(ka, kb)
|
|
||||||
|
|
||||||
def sumPubkeys(self, Ka: bytes, Kb: bytes) -> bytes:
|
|
||||||
return ed25519_add(Ka, Kb)
|
|
||||||
|
|
||||||
def encodeSharedAddress(self, Kbv: bytes, Kbs: bytes) -> str:
|
|
||||||
return wow_util.encode_address(Kbv, Kbs, self._addr_prefix)
|
|
||||||
|
|
||||||
def publishBLockTx(self, kbv: bytes, Kbs: bytes, output_amount: int, feerate: int, unlock_time: int = 0) -> bytes:
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
self.rpc_wallet('refresh')
|
|
||||||
|
|
||||||
Kbv = self.getPubkey(kbv)
|
|
||||||
shared_addr = wow_util.encode_address(Kbv, Kbs, self._addr_prefix)
|
|
||||||
|
|
||||||
params = {'destinations': [{'amount': output_amount, 'address': shared_addr}], 'unlock_time': unlock_time}
|
|
||||||
if self._fee_priority > 0:
|
|
||||||
params['priority'] = self._fee_priority
|
|
||||||
rv = self.rpc_wallet('transfer', params)
|
|
||||||
self._log.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr)
|
|
||||||
tx_hash = bytes.fromhex(rv['tx_hash'])
|
|
||||||
|
|
||||||
return tx_hash
|
|
||||||
|
|
||||||
def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender):
|
|
||||||
with self._mx_wallet:
|
|
||||||
Kbv = self.getPubkey(kbv)
|
|
||||||
address_b58 = wow_util.encode_address(Kbv, Kbs, self._addr_prefix)
|
|
||||||
|
|
||||||
kbv_le = kbv[::-1]
|
|
||||||
params = {
|
|
||||||
'restore_height': restore_height,
|
|
||||||
'filename': address_b58,
|
|
||||||
'address': address_b58,
|
|
||||||
'viewkey': b2h(kbv_le),
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.openWallet(address_b58)
|
|
||||||
except Exception as e:
|
|
||||||
self.createWallet(params)
|
|
||||||
self.openWallet(address_b58)
|
|
||||||
|
|
||||||
self.rpc_wallet('refresh', timeout=self._walletrpctimeoutlong)
|
|
||||||
|
|
||||||
'''
|
|
||||||
# Debug
|
|
||||||
try:
|
|
||||||
current_height = self.rpc_wallet('get_height')['height']
|
|
||||||
self._log.info('findTxB WOW current_height %d\nAddress: %s', current_height, address_b58)
|
|
||||||
except Exception as e:
|
|
||||||
self._log.info('rpc failed %s', str(e))
|
|
||||||
current_height = None # If the transfer is available it will be deep enough
|
|
||||||
# and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
|
|
||||||
'''
|
|
||||||
params = {'transfer_type': 'available'}
|
|
||||||
transfers = self.rpc_wallet('incoming_transfers', params)
|
|
||||||
rv = None
|
|
||||||
if 'transfers' in transfers:
|
|
||||||
for transfer in transfers['transfers']:
|
|
||||||
# unlocked <- wallet->is_transfer_unlocked() checks unlock_time and CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
|
|
||||||
if not transfer['unlocked']:
|
|
||||||
full_tx = self.rpc_wallet('get_transfer_by_txid', {'txid': transfer['tx_hash']})
|
|
||||||
unlock_time = full_tx['transfer']['unlock_time']
|
|
||||||
if unlock_time != 0:
|
|
||||||
self._log.warning('Coin b lock txn is locked: {}, unlock_time {}'.format(transfer['tx_hash'], unlock_time))
|
|
||||||
rv = -1
|
|
||||||
continue
|
|
||||||
if transfer['amount'] == cb_swap_value:
|
|
||||||
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
|
|
||||||
else:
|
|
||||||
self._log.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
|
|
||||||
rv = -1
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def findTxnByHash(self, txid):
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
self.rpc_wallet('refresh', timeout=self._walletrpctimeoutlong)
|
|
||||||
|
|
||||||
try:
|
|
||||||
current_height = self.rpc2('get_height', timeout=self._rpctimeout)['height']
|
|
||||||
self._log.info('findTxnByHash WOW current_height %d\nhash: %s', current_height, txid)
|
|
||||||
except Exception as e:
|
|
||||||
self._log.info('rpc failed %s', str(e))
|
|
||||||
current_height = None # If the transfer is available it will be deep enough
|
|
||||||
|
|
||||||
params = {'transfer_type': 'available'}
|
|
||||||
rv = self.rpc_wallet('incoming_transfers', params)
|
|
||||||
if 'transfers' in rv:
|
|
||||||
for transfer in rv['transfers']:
|
|
||||||
if transfer['tx_hash'] == txid \
|
|
||||||
and (current_height is None or current_height - transfer['block_height'] > self.blocks_confirmed):
|
|
||||||
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': transfer['block_height']}
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def spendBLockTx(self, chain_b_lock_txid: bytes, address_to: str, kbv: bytes, kbs: bytes, cb_swap_value: int, b_fee_rate: int, restore_height: int, spend_actual_balance: bool = False) -> bytes:
|
|
||||||
'''
|
|
||||||
Notes:
|
|
||||||
"Error: No unlocked balance in the specified subaddress(es)" can mean not enough funds after tx fee.
|
|
||||||
'''
|
|
||||||
with self._mx_wallet:
|
|
||||||
Kbv = self.getPubkey(kbv)
|
|
||||||
Kbs = self.getPubkey(kbs)
|
|
||||||
address_b58 = wow_util.encode_address(Kbv, Kbs, self._addr_prefix)
|
|
||||||
|
|
||||||
wallet_filename = address_b58 + '_spend'
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'filename': wallet_filename,
|
|
||||||
'address': address_b58,
|
|
||||||
'viewkey': b2h(kbv[::-1]),
|
|
||||||
'spendkey': b2h(kbs[::-1]),
|
|
||||||
'restore_height': restore_height,
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.openWallet(wallet_filename)
|
|
||||||
except Exception as e:
|
|
||||||
self.createWallet(params)
|
|
||||||
self.openWallet(wallet_filename)
|
|
||||||
|
|
||||||
self.rpc_wallet('refresh')
|
|
||||||
rv = self.rpc_wallet('get_balance')
|
|
||||||
if rv['balance'] < cb_swap_value:
|
|
||||||
self._log.warning('Balance is too low, checking for existing spend.')
|
|
||||||
txns = self.rpc_wallet('get_transfers', {'out': True})
|
|
||||||
if 'out' in txns:
|
|
||||||
txns = txns['out']
|
|
||||||
if len(txns) > 0:
|
|
||||||
txid = txns[0]['txid']
|
|
||||||
self._log.warning(f'spendBLockTx detected spending tx: {txid}.')
|
|
||||||
if txns[0]['address'] == address_b58:
|
|
||||||
return bytes.fromhex(txid)
|
|
||||||
|
|
||||||
self._log.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value))
|
|
||||||
|
|
||||||
if not spend_actual_balance:
|
|
||||||
raise TemporaryError('Invalid balance')
|
|
||||||
|
|
||||||
if spend_actual_balance and rv['balance'] != cb_swap_value:
|
|
||||||
self._log.warning('Spending actual balance {}, not swap value {}.'.format(rv['balance'], cb_swap_value))
|
|
||||||
cb_swap_value = rv['balance']
|
|
||||||
if rv['unlocked_balance'] < cb_swap_value:
|
|
||||||
self._log.error('wallet {} balance {}, expected {}, blocks_to_unlock {}'.format(wallet_filename, rv['unlocked_balance'], cb_swap_value, rv['blocks_to_unlock']))
|
|
||||||
raise TemporaryError('Invalid unlocked_balance')
|
|
||||||
|
|
||||||
params = {'address': address_to}
|
|
||||||
if self._fee_priority > 0:
|
|
||||||
params['priority'] = self._fee_priority
|
|
||||||
|
|
||||||
rv = self.rpc_wallet('sweep_all', params)
|
|
||||||
self._log.debug('sweep_all {}'.format(json.dumps(rv)))
|
|
||||||
|
|
||||||
return bytes.fromhex(rv['tx_hash_list'][0])
|
|
||||||
|
|
||||||
def withdrawCoin(self, value, addr_to: str, sweepall: bool, estimate_fee: bool = False) -> str:
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
self.rpc_wallet('refresh')
|
|
||||||
|
|
||||||
if sweepall:
|
|
||||||
balance = self.rpc_wallet('get_balance')
|
|
||||||
if balance['balance'] != balance['unlocked_balance']:
|
|
||||||
raise ValueError('Balance must be fully confirmed to use sweep all.')
|
|
||||||
self._log.info('WOW {} sweep_all.'.format('estimate fee' if estimate_fee else 'withdraw'))
|
|
||||||
self._log.debug('WOW balance: {}'.format(balance['balance']))
|
|
||||||
params = {'address': addr_to, 'do_not_relay': estimate_fee}
|
|
||||||
if self._fee_priority > 0:
|
|
||||||
params['priority'] = self._fee_priority
|
|
||||||
rv = self.rpc_wallet('sweep_all', params)
|
|
||||||
if estimate_fee:
|
|
||||||
return {'num_txns': len(rv['fee_list']), 'sum_amount': sum(rv['amount_list']), 'sum_fee': sum(rv['fee_list']), 'sum_weight': sum(rv['weight_list'])}
|
|
||||||
return rv['tx_hash_list'][0]
|
|
||||||
|
|
||||||
value_sats: int = make_int(value, self.exp())
|
|
||||||
params = {'destinations': [{'amount': value_sats, 'address': addr_to}], 'do_not_relay': estimate_fee}
|
|
||||||
if self._fee_priority > 0:
|
|
||||||
params['priority'] = self._fee_priority
|
|
||||||
rv = self.rpc_wallet('transfer', params)
|
|
||||||
if estimate_fee:
|
|
||||||
return {'num_txns': 1, 'sum_amount': rv['amount'], 'sum_fee': rv['fee'], 'sum_weight': rv['weight']}
|
|
||||||
return rv['tx_hash']
|
|
||||||
|
|
||||||
def estimateFee(self, value: int, addr_to: str, sweepall: bool) -> str:
|
|
||||||
return self.withdrawCoin(value, addr_to, sweepall, estimate_fee=True)
|
|
||||||
|
|
||||||
def showLockTransfers(self, kbv, Kbs, restore_height):
|
|
||||||
with self._mx_wallet:
|
|
||||||
try:
|
|
||||||
Kbv = self.getPubkey(kbv)
|
|
||||||
address_b58 = wow_util.encode_address(Kbv, Kbs, self._addr_prefix)
|
|
||||||
wallet_file = address_b58 + '_spend'
|
|
||||||
try:
|
|
||||||
self.openWallet(wallet_file)
|
|
||||||
except Exception:
|
|
||||||
wallet_file = address_b58
|
|
||||||
try:
|
|
||||||
self.openWallet(wallet_file)
|
|
||||||
except Exception:
|
|
||||||
self._log.info(f'showLockTransfers trying to create wallet for address {address_b58}.')
|
|
||||||
kbv_le = kbv[::-1]
|
|
||||||
params = {
|
|
||||||
'restore_height': restore_height,
|
|
||||||
'filename': address_b58,
|
|
||||||
'address': address_b58,
|
|
||||||
'viewkey': b2h(kbv_le),
|
|
||||||
}
|
|
||||||
self.createWallet(params)
|
|
||||||
self.openWallet(address_b58)
|
|
||||||
|
|
||||||
self.rpc_wallet('refresh')
|
|
||||||
|
|
||||||
rv = self.rpc_wallet('get_transfers', {'in': True, 'out': True, 'pending': True, 'failed': True})
|
|
||||||
rv['filename'] = wallet_file
|
|
||||||
return rv
|
|
||||||
except Exception as e:
|
|
||||||
return {'error': str(e)}
|
|
||||||
|
|
||||||
def getSpendableBalance(self) -> int:
|
|
||||||
with self._mx_wallet:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
|
|
||||||
self.rpc_wallet('refresh')
|
|
||||||
balance_info = self.rpc_wallet('get_balance')
|
|
||||||
return balance_info['unlocked_balance']
|
|
||||||
|
|
||||||
def changeWalletPassword(self, old_password, new_password):
|
|
||||||
self._log.info('changeWalletPassword - {}'.format(self.ticker()))
|
|
||||||
orig_password = self._wallet_password
|
|
||||||
if old_password != '':
|
|
||||||
self._wallet_password = old_password
|
|
||||||
try:
|
|
||||||
self.openWallet(self._wallet_filename)
|
|
||||||
self.rpc_wallet('change_wallet_password', {'old_password': old_password, 'new_password': new_password})
|
|
||||||
except Exception as e:
|
|
||||||
self._wallet_password = orig_password
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def unlockWallet(self, password: str) -> None:
|
|
||||||
self._log.info('unlockWallet - {}'.format(self.ticker()))
|
|
||||||
self._wallet_password = password
|
|
||||||
|
|
||||||
if not self._have_checked_seed:
|
|
||||||
self._sc.checkWalletSeed(self.coin_type())
|
|
||||||
|
|
||||||
def lockWallet(self) -> None:
|
|
||||||
self._log.info('lockWallet - {}'.format(self.ticker()))
|
|
||||||
self._wallet_password = None
|
|
||||||
|
|
||||||
def isAddressMine(self, address):
|
|
||||||
# TODO
|
|
||||||
return True
|
|
||||||
|
|
||||||
def ensureFunds(self, amount: int) -> None:
|
|
||||||
if self.getSpendableBalance() < amount:
|
|
||||||
raise ValueError('Balance too low')
|
|
||||||
|
|
||||||
def getTransaction(self, txid: bytes):
|
|
||||||
return self.rpc2('get_transactions', {'txs_hashes': [txid.hex(), ]})
|
|
||||||
|
|
|
@ -50,6 +50,10 @@ class XMRInterface(CoinInterface):
|
||||||
def coin_type():
|
def coin_type():
|
||||||
return Coins.XMR
|
return Coins.XMR
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ticker_str() -> int:
|
||||||
|
return Coins.XMR.name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def COIN():
|
def COIN():
|
||||||
return XMR_COIN
|
return XMR_COIN
|
||||||
|
@ -210,7 +214,7 @@ class XMRInterface(CoinInterface):
|
||||||
rv['known_block_count'] = self.rpc('get_block_count', timeout=self._rpctimeout)['count']
|
rv['known_block_count'] = self.rpc('get_block_count', timeout=self._rpctimeout)['count']
|
||||||
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
rv['verificationprogress'] = rv['blocks'] / rv['known_block_count']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log.warning('XMR get_block_count failed with: %s', str(e))
|
self._log.warning(f'{self.ticker_str()} get_block_count failed with: {e}')
|
||||||
rv['verificationprogress'] = 0.0
|
rv['verificationprogress'] = 0.0
|
||||||
|
|
||||||
return rv
|
return rv
|
||||||
|
@ -391,7 +395,7 @@ class XMRInterface(CoinInterface):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
current_height = self.rpc2('get_height', timeout=self._rpctimeout)['height']
|
current_height = self.rpc2('get_height', timeout=self._rpctimeout)['height']
|
||||||
self._log.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid)
|
self._log.info(f'findTxnByHash {self.ticker_str()} current_height {current_height}\nhash: {txid}')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log.info('rpc failed %s', str(e))
|
self._log.info('rpc failed %s', str(e))
|
||||||
current_height = None # If the transfer is available it will be deep enough
|
current_height = None # If the transfer is available it will be deep enough
|
||||||
|
@ -475,8 +479,8 @@ class XMRInterface(CoinInterface):
|
||||||
balance = self.rpc_wallet('get_balance')
|
balance = self.rpc_wallet('get_balance')
|
||||||
if balance['balance'] != balance['unlocked_balance']:
|
if balance['balance'] != balance['unlocked_balance']:
|
||||||
raise ValueError('Balance must be fully confirmed to use sweep all.')
|
raise ValueError('Balance must be fully confirmed to use sweep all.')
|
||||||
self._log.info('XMR {} sweep_all.'.format('estimate fee' if estimate_fee else 'withdraw'))
|
self._log.info('{} {} sweep_all.'.format(self.ticker_str(), 'estimate fee' if estimate_fee else 'withdraw'))
|
||||||
self._log.debug('XMR balance: {}'.format(balance['balance']))
|
self._log.debug('{} balance: {}'.format(self.ticker_str(), balance['balance']))
|
||||||
params = {'address': addr_to, 'do_not_relay': estimate_fee}
|
params = {'address': addr_to, 'do_not_relay': estimate_fee}
|
||||||
if self._fee_priority > 0:
|
if self._fee_priority > 0:
|
||||||
params['priority'] = self._fee_priority
|
params['priority'] = self._fee_priority
|
||||||
|
|
|
@ -1,258 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import socks
|
|
||||||
import time
|
|
||||||
import urllib
|
|
||||||
import hashlib
|
|
||||||
from xmlrpc.client import (
|
|
||||||
Fault,
|
|
||||||
Transport,
|
|
||||||
SafeTransport,
|
|
||||||
)
|
|
||||||
from sockshandler import SocksiPyConnection
|
|
||||||
from .util import jsonDecimal
|
|
||||||
|
|
||||||
|
|
||||||
class SocksTransport(Transport):
|
|
||||||
|
|
||||||
def set_proxy(self, proxy_host, proxy_port):
|
|
||||||
self.proxy_host = proxy_host
|
|
||||||
self.proxy_port = proxy_port
|
|
||||||
|
|
||||||
self.proxy_type = socks.PROXY_TYPE_SOCKS5
|
|
||||||
self.proxy_rdns = True
|
|
||||||
self.proxy_username = None
|
|
||||||
self.proxy_password = None
|
|
||||||
|
|
||||||
def make_connection(self, host):
|
|
||||||
# return an existing connection if possible. This allows
|
|
||||||
# HTTP/1.1 keep-alive.
|
|
||||||
if self._connection and host == self._connection[0]:
|
|
||||||
return self._connection[1]
|
|
||||||
# create a HTTP connection object from a host descriptor
|
|
||||||
chost, self._extra_headers, x509 = self.get_host_info(host)
|
|
||||||
self._connection = host, SocksiPyConnection(self.proxy_type, self.proxy_host, self.proxy_port, self.proxy_rdns, self.proxy_username, self.proxy_password, chost)
|
|
||||||
return self._connection[1]
|
|
||||||
|
|
||||||
|
|
||||||
class JsonrpcDigest():
|
|
||||||
# __getattr__ complicates extending ServerProxy
|
|
||||||
def __init__(self, uri, transport=None, encoding=None, verbose=False,
|
|
||||||
allow_none=False, use_datetime=False, use_builtin_types=False,
|
|
||||||
*, context=None):
|
|
||||||
|
|
||||||
parsed = urllib.parse.urlparse(uri)
|
|
||||||
if parsed.scheme not in ('http', 'https'):
|
|
||||||
raise OSError('unsupported XML-RPC protocol')
|
|
||||||
self.__host = parsed.netloc
|
|
||||||
self.__handler = parsed.path
|
|
||||||
|
|
||||||
if transport is None:
|
|
||||||
handler = SafeTransport if parsed.scheme == 'https' else Transport
|
|
||||||
extra_kwargs = {}
|
|
||||||
transport = handler(use_datetime=use_datetime,
|
|
||||||
use_builtin_types=use_builtin_types,
|
|
||||||
**extra_kwargs)
|
|
||||||
self.__transport = transport
|
|
||||||
|
|
||||||
self.__encoding = encoding or 'utf-8'
|
|
||||||
self.__verbose = verbose
|
|
||||||
self.__allow_none = allow_none
|
|
||||||
|
|
||||||
self.__request_id = 0
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.__transport is not None:
|
|
||||||
self.__transport.close()
|
|
||||||
|
|
||||||
def request_id(self):
|
|
||||||
return self.__request_id
|
|
||||||
|
|
||||||
def post_request(self, method, params, timeout=None):
|
|
||||||
try:
|
|
||||||
connection = self.__transport.make_connection(self.__host)
|
|
||||||
if timeout:
|
|
||||||
connection.timeout = timeout
|
|
||||||
headers = self.__transport._extra_headers[:]
|
|
||||||
|
|
||||||
connection.putrequest('POST', self.__handler)
|
|
||||||
headers.append(('Content-Type', 'application/json'))
|
|
||||||
headers.append(('User-Agent', 'jsonrpc'))
|
|
||||||
self.__transport.send_headers(connection, headers)
|
|
||||||
self.__transport.send_content(connection, '' if params is None else json.dumps(params, default=jsonDecimal).encode('utf-8'))
|
|
||||||
self.__request_id += 1
|
|
||||||
|
|
||||||
resp = connection.getresponse()
|
|
||||||
return resp.read()
|
|
||||||
|
|
||||||
except Fault:
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
self.__transport.close()
|
|
||||||
raise
|
|
||||||
|
|
||||||
def json_request(self, request_body, username='', password='', timeout=None):
|
|
||||||
try:
|
|
||||||
connection = self.__transport.make_connection(self.__host)
|
|
||||||
if timeout:
|
|
||||||
connection.timeout = timeout
|
|
||||||
|
|
||||||
headers = self.__transport._extra_headers[:]
|
|
||||||
|
|
||||||
connection.putrequest('POST', self.__handler)
|
|
||||||
headers.append(('Content-Type', 'application/json'))
|
|
||||||
headers.append(('Connection', 'keep-alive'))
|
|
||||||
self.__transport.send_headers(connection, headers)
|
|
||||||
self.__transport.send_content(connection, json.dumps(request_body, default=jsonDecimal).encode('utf-8') if request_body else '')
|
|
||||||
resp = connection.getresponse()
|
|
||||||
|
|
||||||
if resp.status == 401:
|
|
||||||
resp_headers = resp.getheaders()
|
|
||||||
v = resp.read()
|
|
||||||
|
|
||||||
algorithm = ''
|
|
||||||
realm = ''
|
|
||||||
nonce = ''
|
|
||||||
for h in resp_headers:
|
|
||||||
if h[0] != 'WWW-authenticate':
|
|
||||||
continue
|
|
||||||
fields = h[1].split(',')
|
|
||||||
for f in fields:
|
|
||||||
key, value = f.split('=', 1)
|
|
||||||
if key == 'algorithm' and value != 'MD5':
|
|
||||||
break
|
|
||||||
if key == 'realm':
|
|
||||||
realm = value.strip('"')
|
|
||||||
if key == 'nonce':
|
|
||||||
nonce = value.strip('"')
|
|
||||||
if realm != '' and nonce != '':
|
|
||||||
break
|
|
||||||
|
|
||||||
if realm == '' or nonce == '':
|
|
||||||
raise ValueError('Authenticate header not found.')
|
|
||||||
|
|
||||||
path = self.__handler
|
|
||||||
HA1 = hashlib.md5(f'{username}:{realm}:{password}'.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
http_method = 'POST'
|
|
||||||
HA2 = hashlib.md5(f'{http_method}:{path}'.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
ncvalue = '{:08x}'.format(1)
|
|
||||||
s = ncvalue.encode('utf-8')
|
|
||||||
s += nonce.encode('utf-8')
|
|
||||||
s += time.ctime().encode('utf-8')
|
|
||||||
s += os.urandom(8)
|
|
||||||
cnonce = (hashlib.sha1(s).hexdigest()[:16])
|
|
||||||
|
|
||||||
# MD5-SESS
|
|
||||||
HA1 = hashlib.md5(f'{HA1}:{nonce}:{cnonce}'.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
respdig = hashlib.md5(f'{HA1}:{nonce}:{ncvalue}:{cnonce}:auth:{HA2}'.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
header_value = f'Digest username="{username}", realm="{realm}", nonce="{nonce}", uri="{path}", response="{respdig}", algorithm="MD5-sess", qop="auth", nc={ncvalue}, cnonce="{cnonce}"'
|
|
||||||
headers = self.__transport._extra_headers[:]
|
|
||||||
headers.append(('Authorization', header_value))
|
|
||||||
|
|
||||||
connection.putrequest('POST', self.__handler)
|
|
||||||
headers.append(('Content-Type', 'application/json'))
|
|
||||||
headers.append(('Connection', 'keep-alive'))
|
|
||||||
self.__transport.send_headers(connection, headers)
|
|
||||||
self.__transport.send_content(connection, json.dumps(request_body, default=jsonDecimal).encode('utf-8') if request_body else '')
|
|
||||||
resp = connection.getresponse()
|
|
||||||
|
|
||||||
self.__request_id += 1
|
|
||||||
return resp.read()
|
|
||||||
|
|
||||||
except Fault:
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
self.__transport.close()
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def callrpc_wow(rpc_port, method, params=[], rpc_host='127.0.0.1', path='json_rpc', auth=None, timeout=120, transport=None, tag=''):
|
|
||||||
# auth is a tuple: (username, password)
|
|
||||||
try:
|
|
||||||
if rpc_host.count('://') > 0:
|
|
||||||
url = '{}:{}/{}'.format(rpc_host, rpc_port, path)
|
|
||||||
else:
|
|
||||||
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, path)
|
|
||||||
|
|
||||||
x = JsonrpcDigest(url, transport=transport)
|
|
||||||
request_body = {
|
|
||||||
'method': method,
|
|
||||||
'params': params,
|
|
||||||
'jsonrpc': '2.0',
|
|
||||||
'id': x.request_id()
|
|
||||||
}
|
|
||||||
if auth:
|
|
||||||
v = x.json_request(request_body, username=auth[0], password=auth[1], timeout=timeout)
|
|
||||||
else:
|
|
||||||
v = x.json_request(request_body, timeout=timeout)
|
|
||||||
x.close()
|
|
||||||
r = json.loads(v.decode('utf-8'))
|
|
||||||
except Exception as ex:
|
|
||||||
raise ValueError('{}RPC Server Error: {}'.format(tag, str(ex)))
|
|
||||||
|
|
||||||
if 'error' in r and r['error'] is not None:
|
|
||||||
raise ValueError(tag + 'RPC error ' + str(r['error']))
|
|
||||||
|
|
||||||
return r['result']
|
|
||||||
|
|
||||||
|
|
||||||
def callrpc_wow2(rpc_port: int, method: str, params=None, auth=None, rpc_host='127.0.0.1', timeout=120, transport=None, tag=''):
|
|
||||||
try:
|
|
||||||
if rpc_host.count('://') > 0:
|
|
||||||
url = '{}:{}/{}'.format(rpc_host, rpc_port, method)
|
|
||||||
else:
|
|
||||||
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, method)
|
|
||||||
|
|
||||||
x = JsonrpcDigest(url, transport=transport)
|
|
||||||
if auth:
|
|
||||||
v = x.json_request(params, username=auth[0], password=auth[1], timeout=timeout)
|
|
||||||
else:
|
|
||||||
v = x.json_request(params, timeout=timeout)
|
|
||||||
x.close()
|
|
||||||
r = json.loads(v.decode('utf-8'))
|
|
||||||
except Exception as ex:
|
|
||||||
raise ValueError('{}RPC Server Error: {}'.format(tag, str(ex)))
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def make_wow_rpc2_func(port, auth, host='127.0.0.1', proxy_host=None, proxy_port=None, default_timeout=120, tag=''):
|
|
||||||
port = port
|
|
||||||
auth = auth
|
|
||||||
host = host
|
|
||||||
transport = None
|
|
||||||
default_timeout = default_timeout
|
|
||||||
tag = tag
|
|
||||||
|
|
||||||
if proxy_host:
|
|
||||||
transport = SocksTransport()
|
|
||||||
transport.set_proxy(proxy_host, proxy_port)
|
|
||||||
|
|
||||||
def rpc_func(method, params=None, wallet=None, timeout=default_timeout):
|
|
||||||
nonlocal port, auth, host, transport, tag
|
|
||||||
return callrpc_wow2(port, method, params, auth=auth, rpc_host=host, timeout=timeout, transport=transport, tag=tag)
|
|
||||||
return rpc_func
|
|
||||||
|
|
||||||
|
|
||||||
def make_wow_rpc_func(port, auth, host='127.0.0.1', proxy_host=None, proxy_port=None, default_timeout=120, tag=''):
|
|
||||||
port = port
|
|
||||||
auth = auth
|
|
||||||
host = host
|
|
||||||
transport = None
|
|
||||||
default_timeout = default_timeout
|
|
||||||
tag = tag
|
|
||||||
|
|
||||||
if proxy_host:
|
|
||||||
transport = SocksTransport()
|
|
||||||
transport.set_proxy(proxy_host, proxy_port)
|
|
||||||
|
|
||||||
def rpc_func(method, params=None, wallet=None, timeout=default_timeout):
|
|
||||||
nonlocal port, auth, host, transport, tag
|
|
||||||
return callrpc_wow(port, method, params, rpc_host=host, auth=auth, timeout=timeout, transport=transport, tag=tag)
|
|
||||||
return rpc_func
|
|
|
@ -85,8 +85,9 @@ SKIP_GPG_VALIDATION = toBool(os.getenv('SKIP_GPG_VALIDATION', 'false'))
|
||||||
|
|
||||||
known_coins = {
|
known_coins = {
|
||||||
'particl': (PARTICL_VERSION, PARTICL_VERSION_TAG, ('tecnovert',)),
|
'particl': (PARTICL_VERSION, PARTICL_VERSION_TAG, ('tecnovert',)),
|
||||||
'litecoin': (LITECOIN_VERSION, LITECOIN_VERSION_TAG, ('davidburkett38',)),
|
|
||||||
'bitcoin': (BITCOIN_VERSION, BITCOIN_VERSION_TAG, ('laanwj',)),
|
'bitcoin': (BITCOIN_VERSION, BITCOIN_VERSION_TAG, ('laanwj',)),
|
||||||
|
'litecoin': (LITECOIN_VERSION, LITECOIN_VERSION_TAG, ('davidburkett38',)),
|
||||||
|
'decred': (DCR_VERSION, DCR_VERSION_TAG, ('decred_release',)),
|
||||||
'namecoin': ('0.18.0', '', ('JeremyRand',)),
|
'namecoin': ('0.18.0', '', ('JeremyRand',)),
|
||||||
'monero': (MONERO_VERSION, MONERO_VERSION_TAG, ('binaryfate',)),
|
'monero': (MONERO_VERSION, MONERO_VERSION_TAG, ('binaryfate',)),
|
||||||
'wownero': (WOWNERO_VERSION, WOWNERO_VERSION_TAG, ('wowario',)),
|
'wownero': (WOWNERO_VERSION, WOWNERO_VERSION_TAG, ('wowario',)),
|
||||||
|
@ -94,7 +95,6 @@ known_coins = {
|
||||||
'dash': (DASH_VERSION, DASH_VERSION_TAG, ('pasta',)),
|
'dash': (DASH_VERSION, DASH_VERSION_TAG, ('pasta',)),
|
||||||
'firo': (FIRO_VERSION, FIRO_VERSION_TAG, ('reuben',)),
|
'firo': (FIRO_VERSION, FIRO_VERSION_TAG, ('reuben',)),
|
||||||
'navcoin': (NAV_VERSION, NAV_VERSION_TAG, ('nav_builder',)),
|
'navcoin': (NAV_VERSION, NAV_VERSION_TAG, ('nav_builder',)),
|
||||||
'decred': (DCR_VERSION, DCR_VERSION_TAG, ('decred_release',)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disabled_coins = [
|
disabled_coins = [
|
||||||
|
|
|
@ -118,7 +118,9 @@ def startXmrWalletDaemon(node_dir, bin_dir, wallet_bin, opts=[]):
|
||||||
config_to_remove = ['daemon-address=', 'untrusted-daemon=', 'trusted-daemon=', 'proxy=']
|
config_to_remove = ['daemon-address=', 'untrusted-daemon=', 'trusted-daemon=', 'proxy=']
|
||||||
|
|
||||||
data_dir = os.path.expanduser(node_dir)
|
data_dir = os.path.expanduser(node_dir)
|
||||||
config_path = os.path.join(data_dir, 'monero_wallet.conf')
|
|
||||||
|
wallet_config_filename = 'wownero-wallet-rpc.conf' if wallet_bin.startswith('wow') else 'monero_wallet.conf'
|
||||||
|
config_path = os.path.join(data_dir, wallet_config_filename)
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(config_path):
|
||||||
args += ['--config-file=' + config_path]
|
args += ['--config-file=' + config_path]
|
||||||
with open(config_path) as fp:
|
with open(config_path) as fp:
|
||||||
|
|
Loading…
Reference in a new issue