mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-05 18:38:09 +01:00
basicswap-prepare tries to initialise coin wallets from Particl mnemonic
Bitcoin 0.20: 'Cannot set a new HD seed while still in Initial Block Download.' Removed in 0.21
This commit is contained in:
@@ -49,6 +49,9 @@ class BaseApp:
|
||||
self.log = logging.getLogger(self.log_name)
|
||||
self.log.propagate = False
|
||||
|
||||
# Remove any existing handlers
|
||||
self.log.handlers = []
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
||||
stream_stdout = logging.StreamHandler()
|
||||
if self.log_name != 'BasicSwap':
|
||||
@@ -81,6 +84,12 @@ class BaseApp:
|
||||
testnet_name = '' if self.chain == 'mainnet' else chainparams[coin][self.chain].get('name', self.chain)
|
||||
return os.path.join(datadir, testnet_name)
|
||||
|
||||
def getCoinIdFromName(self, coin_name):
|
||||
for c, params in chainparams.items():
|
||||
if coin_name.lower() == params['name'].lower():
|
||||
return c
|
||||
raise ValueError('Unknown coin: {}'.format(coin_name))
|
||||
|
||||
def getTicker(self, coin_type):
|
||||
ticker = chainparams[coin_type]['ticker']
|
||||
if self.chain == 'testnet':
|
||||
|
||||
@@ -551,7 +551,6 @@ class BasicSwap(BaseApp):
|
||||
self.coin_clients[coin]['walletrpcauth'] = (chain_client_settings['walletrpcuser'], chain_client_settings['walletrpcpassword'])
|
||||
else:
|
||||
raise ValueError('Missing XMR wallet rpc credentials.')
|
||||
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
||||
|
||||
def ci(self, coin): # coin interface
|
||||
return self.coin_clients[coin]['interface']
|
||||
@@ -593,17 +592,17 @@ class BasicSwap(BaseApp):
|
||||
try:
|
||||
with open(pidfilepath, 'rb') as fp:
|
||||
datadir_pid = int(fp.read().decode('utf-8'))
|
||||
assert(datadir_pid == cc['pid'])
|
||||
assert(datadir_pid == cc['pid']), 'Mismatched pid'
|
||||
assert(os.path.exists(authcookiepath))
|
||||
except Exception:
|
||||
time.sleep(0.5)
|
||||
try:
|
||||
if os.name != 'nt' or cc['core_version_group'] > 17: # litecoin on windows doesn't write a pid file
|
||||
assert(datadir_pid == cc['pid'])
|
||||
assert(datadir_pid == cc['pid']), 'Mismatched pid'
|
||||
with open(authcookiepath, 'rb') as fp:
|
||||
cc['rpcauth'] = fp.read().decode('utf-8')
|
||||
except Exception:
|
||||
self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s', str(coin), authcookiepath, datadir_pid, cc['pid'])
|
||||
except Exception as e:
|
||||
self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s. Error: %s', str(coin), authcookiepath, datadir_pid, cc['pid'], str(e))
|
||||
raise ValueError('Error, terminating')
|
||||
|
||||
def createCoinInterface(self, coin):
|
||||
@@ -626,6 +625,9 @@ class BasicSwap(BaseApp):
|
||||
self.log.info('%s Core version %d', chainparams[c]['name'].capitalize(), core_version)
|
||||
self.coin_clients[c]['core_version'] = core_version
|
||||
|
||||
if c == Coins.XMR:
|
||||
self.coin_clients[c]['interface'].ensureWalletExists()
|
||||
|
||||
if c == Coins.PART:
|
||||
self.coin_clients[c]['have_spent_index'] = self.coin_clients[c]['interface'].haveSpentIndex()
|
||||
|
||||
@@ -636,6 +638,8 @@ class BasicSwap(BaseApp):
|
||||
self.initialise()
|
||||
|
||||
def stopDaemon(self, coin):
|
||||
if coin == Coins.XMR:
|
||||
return
|
||||
num_tries = 10
|
||||
authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie')
|
||||
stopping = False
|
||||
@@ -697,6 +701,19 @@ class BasicSwap(BaseApp):
|
||||
if synced < 1.0:
|
||||
raise ValueError('{} chain is still syncing, currently at {}.'.format(self.coin_clients[c]['name'], synced))
|
||||
|
||||
def initialiseWallet(self, coin_type):
|
||||
ci = self.ci(coin_type)
|
||||
self.log.info('Initialising {} wallet.'.format(ci.coin_name()))
|
||||
|
||||
if coin_type == Coins.XMR:
|
||||
key_view = self.getWalletKey(coin_type, 1, for_ed25519=True)
|
||||
key_spend = self.getWalletKey(coin_type, 2, for_ed25519=True)
|
||||
ci.initialiseWallet(key_view, key_spend)
|
||||
return
|
||||
|
||||
root_key = self.getWalletKey(coin_type, 1)
|
||||
ci.initialiseWallet(root_key)
|
||||
|
||||
def setIntKV(self, str_key, int_val):
|
||||
session = scoped_session(self.session_factory)
|
||||
kv = session.query(DBKVInt).filter_by(key=str_key).first()
|
||||
@@ -963,19 +980,8 @@ class BasicSwap(BaseApp):
|
||||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_xmr=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
ci = self.ci(coin_to)
|
||||
|
||||
days = offer_created_at // 86400
|
||||
secs = offer_created_at - days * 86400
|
||||
key_path_base = '44445555h/999999/{}/{}/{}/{}/{}/{}'.format(int(coin_from), int(coin_to), days, secs, contract_count, key_no)
|
||||
|
||||
if not for_xmr:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
def grindForEd25519Key(self, coin_type, evkey, key_path_base):
|
||||
ci = self.ci(coin_type)
|
||||
nonce = 1
|
||||
while True:
|
||||
key_path = key_path_base + '/{}'.format(nonce)
|
||||
@@ -986,7 +992,34 @@ class BasicSwap(BaseApp):
|
||||
return privkey
|
||||
nonce += 1
|
||||
if nonce > 1000:
|
||||
raise ValueError('getKeyForXMR failed')
|
||||
raise ValueError('grindForEd25519Key failed')
|
||||
|
||||
def getWalletKey(self, coin_type, key_num, for_ed25519=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
|
||||
key_path_base = '44445555h/1h/{}/{}'.format(int(coin_type), key_num)
|
||||
|
||||
if not for_ed25519:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
return self.grindForEd25519Key(coin_type, evkey, key_path_base)
|
||||
|
||||
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_ed25519=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
ci = self.ci(coin_to)
|
||||
|
||||
days = offer_created_at // 86400
|
||||
secs = offer_created_at - days * 86400
|
||||
key_path_base = '44445555h/999999/{}/{}/{}/{}/{}/{}'.format(int(coin_from), int(coin_to), days, secs, contract_count, key_no)
|
||||
|
||||
if not for_ed25519:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
return self.grindForEd25519Key(coin_to, evkey, key_path_base)
|
||||
|
||||
def getContractPubkey(self, date, contract_count):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
@@ -1550,8 +1583,8 @@ class BasicSwap(BaseApp):
|
||||
xmr_swap.contract_count = self.getNewContractId()
|
||||
xmr_swap.dest_af = msg_buf.dest_af
|
||||
xmr_swap.b_restore_height = self.ci(coin_to).getChainHeight()
|
||||
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 1, for_xmr=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 1, for_ed25519=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
|
||||
kaf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 3)
|
||||
karf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 4)
|
||||
@@ -1660,8 +1693,8 @@ class BasicSwap(BaseApp):
|
||||
|
||||
contract_secret = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 1)
|
||||
|
||||
kbvl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
kbvl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_ed25519=True)
|
||||
|
||||
kal = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 4)
|
||||
karl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 5)
|
||||
@@ -3746,7 +3779,7 @@ class BasicSwap(BaseApp):
|
||||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
kaf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3)
|
||||
|
||||
al_lock_spend_sig = ci_from.decryptOtVES(kbsf, xmr_swap.al_lock_spend_tx_esig)
|
||||
@@ -3801,7 +3834,7 @@ class BasicSwap(BaseApp):
|
||||
kbsf = ci_from.recoverEncKey(xmr_swap.al_lock_spend_tx_esig, xmr_swap.al_lock_spend_tx_sig, xmr_swap.pkasf)
|
||||
assert(kbsf is not None)
|
||||
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_ed25519=True)
|
||||
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||
|
||||
address_to = ci_to.getMainWalletAddress()
|
||||
@@ -3835,7 +3868,7 @@ class BasicSwap(BaseApp):
|
||||
kbsl = ci_from.recoverEncKey(xmr_swap.af_lock_refund_spend_tx_esig, af_lock_refund_spend_tx_sig, xmr_swap.pkasl)
|
||||
assert(kbsl is not None)
|
||||
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_ed25519=True)
|
||||
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||
|
||||
address_to = ci_to.getMainWalletAddress()
|
||||
@@ -3874,7 +3907,7 @@ class BasicSwap(BaseApp):
|
||||
xmr_swap.af_lock_refund_spend_tx_esig = msg_data.af_lock_refund_spend_tx_esig
|
||||
xmr_swap.af_lock_refund_tx_sig = msg_data.af_lock_refund_tx_sig
|
||||
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_ed25519=True)
|
||||
karl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 5)
|
||||
|
||||
xmr_swap.af_lock_refund_spend_tx_sig = ci_from.decryptOtVES(kbsl, xmr_swap.af_lock_refund_spend_tx_esig)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2019 tecnovert
|
||||
# Copyright (c) 2019-2020 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@@ -70,6 +70,7 @@ chainparams = {
|
||||
'rpcport': 8332,
|
||||
'pubkey_address': 0,
|
||||
'script_address': 5,
|
||||
'key_prefix': 128,
|
||||
'hrp': 'bc',
|
||||
'bip44': 0,
|
||||
'min_amount': 1000,
|
||||
@@ -79,6 +80,7 @@ chainparams = {
|
||||
'rpcport': 18332,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 196,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'tb',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
@@ -89,6 +91,7 @@ chainparams = {
|
||||
'rpcport': 18443,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 196,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'bcrt',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
@@ -105,6 +108,7 @@ chainparams = {
|
||||
'rpcport': 9332,
|
||||
'pubkey_address': 48,
|
||||
'script_address': 50,
|
||||
'key_prefix': 176,
|
||||
'hrp': 'ltc',
|
||||
'bip44': 2,
|
||||
'min_amount': 1000,
|
||||
@@ -114,6 +118,7 @@ chainparams = {
|
||||
'rpcport': 19332,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 58,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'tltc',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
@@ -124,6 +129,7 @@ chainparams = {
|
||||
'rpcport': 19443,
|
||||
'pubkey_address': 111,
|
||||
'script_address': 58,
|
||||
'key_prefix': 239,
|
||||
'hrp': 'rltc',
|
||||
'bip44': 1,
|
||||
'min_amount': 1000,
|
||||
|
||||
@@ -8,6 +8,7 @@ import os
|
||||
|
||||
CONFIG_FILENAME = 'basicswap.json'
|
||||
DEFAULT_DATADIR = '~/.basicswap'
|
||||
DEFAULT_ALLOW_CORS = False
|
||||
TEST_DATADIRS = os.path.expanduser(os.getenv('DATADIRS', '/tmp/basicswap'))
|
||||
|
||||
bin_suffix = ('.exe' if os.name == 'nt' else '')
|
||||
|
||||
@@ -17,6 +17,7 @@ from .util import (
|
||||
dumpj,
|
||||
format_amount,
|
||||
make_int,
|
||||
toWIF,
|
||||
decodeAddress)
|
||||
from coincurve.keys import (
|
||||
PublicKey)
|
||||
@@ -131,6 +132,16 @@ class BTCInterface(CoinInterface):
|
||||
def getBlockchainInfo(self):
|
||||
return self.rpc_callback('getblockchaininfo')
|
||||
|
||||
def initialiseWallet(self, key_bytes):
|
||||
wif_prefix = chainparams[self.coin_type()][self._network]['key_prefix']
|
||||
key_wif = toWIF(wif_prefix, key_bytes)
|
||||
|
||||
try:
|
||||
self.rpc_callback('sethdseed', [True, key_wif])
|
||||
except Exception as e:
|
||||
# < 0.21: Cannot set a new HD seed while still in Initial Block Download.
|
||||
logging.error('sethdseed failed: {}'.format(str(e)))
|
||||
|
||||
def getWalletInfo(self):
|
||||
return self.rpc_callback('getwalletinfo')
|
||||
|
||||
|
||||
@@ -40,3 +40,6 @@ class PARTInterface(BTCInterface):
|
||||
version = self.getDaemonVersion()
|
||||
index_info = self.rpc_callback('getinsightinfo' if int(str(version)[:2]) > 19 else 'getindexinfo')
|
||||
return index_info['spentindex']
|
||||
|
||||
def initialiseWallet(self, key):
|
||||
raise ValueError('TODO')
|
||||
|
||||
@@ -65,11 +65,45 @@ class XMRInterface(CoinInterface):
|
||||
def setWalletFilename(self, wallet_filename):
|
||||
self._wallet_filename = wallet_filename
|
||||
|
||||
def initialiseWallet(self, key_view, key_spend, restore_height=None):
|
||||
try:
|
||||
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
|
||||
# TODO: Check address
|
||||
return # Wallet exists
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
try:
|
||||
if restore_height is None:
|
||||
restore_height = self.getChainHeight()
|
||||
except Exception as e:
|
||||
logging.warning('Unable to get restore_height, set to zero. Error: {}'.format(str(e)))
|
||||
restore_height = 0
|
||||
|
||||
Kbv = self.getPubkey(key_view)
|
||||
Kbs = self.getPubkey(key_spend)
|
||||
address_b58 = xmr_util.encode_address(Kbv, Kbs)
|
||||
|
||||
params = {
|
||||
'filename': self._wallet_filename,
|
||||
'address': address_b58,
|
||||
'viewkey': b2h(key_view[::-1]),
|
||||
'spendkey': b2h(key_spend[::-1]),
|
||||
'restore_height': restore_height,
|
||||
}
|
||||
rv = self.rpc_wallet_cb('generate_from_keys', params)
|
||||
logging.info('generate_from_keys %s', dumpj(rv))
|
||||
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
|
||||
|
||||
def ensureWalletExists(self):
|
||||
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
|
||||
|
||||
def testDaemonRPC(self):
|
||||
self.rpc_wallet_cb('get_languages')
|
||||
|
||||
def getDaemonVersion(self):
|
||||
return self.rpc_cb('get_version')['version']
|
||||
return self.rpc_wallet_cb('get_version')['version']
|
||||
#return self.rpc_cb('get_version')['version']
|
||||
|
||||
def getBlockchainInfo(self):
|
||||
rv = {}
|
||||
|
||||
@@ -15,7 +15,7 @@ class Peer:
|
||||
|
||||
|
||||
class Network:
|
||||
def __init__(self, network_port, network_key):
|
||||
self._network_port = network_port
|
||||
def __init__(self, p2p_port, network_key):
|
||||
self._p2p_port = p2p_port
|
||||
self._network_key = network_key
|
||||
self._peers = []
|
||||
|
||||
Reference in New Issue
Block a user