Merge pull request #289 from tecnovert/namecoin_v28

Namecoin v28
This commit is contained in:
tecnovert
2025-04-01 18:33:52 +00:00
committed by GitHub
28 changed files with 849 additions and 1012 deletions

View File

@@ -391,7 +391,7 @@ class BasicSwap(BaseApp):
Coins.PART_BLIND, Coins.PART_BLIND,
Coins.BCH, Coins.BCH,
) )
self.coins_without_segwit = (Coins.PIVX, Coins.DASH, Coins.NMC) self.coins_without_segwit = (Coins.PIVX, Coins.DASH)
# TODO: Adjust ranges # TODO: Adjust ranges
self.min_delay_event = self.get_int_setting("min_delay_event", 10, 0, 20 * 60) self.min_delay_event = self.get_int_setting("min_delay_event", 10, 0, 20 * 60)

View File

@@ -52,11 +52,17 @@ PARTICL_VERSION = os.getenv("PARTICL_VERSION", "23.2.7.0")
PARTICL_VERSION_TAG = os.getenv("PARTICL_VERSION_TAG", "") PARTICL_VERSION_TAG = os.getenv("PARTICL_VERSION_TAG", "")
PARTICL_LINUX_EXTRA = os.getenv("PARTICL_LINUX_EXTRA", "nousb") PARTICL_LINUX_EXTRA = os.getenv("PARTICL_LINUX_EXTRA", "nousb")
BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "28.0")
BITCOIN_VERSION_TAG = os.getenv("BITCOIN_VERSION_TAG", "")
LITECOIN_VERSION = os.getenv("LITECOIN_VERSION", "0.21.4") LITECOIN_VERSION = os.getenv("LITECOIN_VERSION", "0.21.4")
LITECOIN_VERSION_TAG = os.getenv("LITECOIN_VERSION_TAG", "") LITECOIN_VERSION_TAG = os.getenv("LITECOIN_VERSION_TAG", "")
BITCOIN_VERSION = os.getenv("BITCOIN_VERSION", "28.0") DCR_VERSION = os.getenv("DCR_VERSION", "1.8.1")
BITCOIN_VERSION_TAG = os.getenv("BITCOIN_VERSION_TAG", "") DCR_VERSION_TAG = os.getenv("DCR_VERSION_TAG", "")
NMC_VERSION = os.getenv("NMC_VERSION", "28.0")
NMC_VERSION_TAG = os.getenv("NMC_VERSION_TAG", "")
MONERO_VERSION = os.getenv("MONERO_VERSION", "0.18.3.4") MONERO_VERSION = os.getenv("MONERO_VERSION", "0.18.3.4")
MONERO_VERSION_TAG = os.getenv("MONERO_VERSION_TAG", "") MONERO_VERSION_TAG = os.getenv("MONERO_VERSION_TAG", "")
@@ -82,9 +88,6 @@ FIRO_VERSION_TAG = os.getenv("FIRO_VERSION_TAG", "")
NAV_VERSION = os.getenv("NAV_VERSION", "7.0.3") NAV_VERSION = os.getenv("NAV_VERSION", "7.0.3")
NAV_VERSION_TAG = os.getenv("NAV_VERSION_TAG", "") NAV_VERSION_TAG = os.getenv("NAV_VERSION_TAG", "")
DCR_VERSION = os.getenv("DCR_VERSION", "1.8.1")
DCR_VERSION_TAG = os.getenv("DCR_VERSION_TAG", "")
BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "28.0.1") BITCOINCASH_VERSION = os.getenv("BITCOINCASH_VERSION", "28.0.1")
BITCOINCASH_VERSION_TAG = os.getenv("BITCOINCASH_VERSION_TAG", "") BITCOINCASH_VERSION_TAG = os.getenv("BITCOINCASH_VERSION_TAG", "")
@@ -103,7 +106,7 @@ known_coins = {
"bitcoin": (BITCOIN_VERSION, BITCOIN_VERSION_TAG, ("laanwj",)), "bitcoin": (BITCOIN_VERSION, BITCOIN_VERSION_TAG, ("laanwj",)),
"litecoin": (LITECOIN_VERSION, LITECOIN_VERSION_TAG, ("davidburkett38",)), "litecoin": (LITECOIN_VERSION, LITECOIN_VERSION_TAG, ("davidburkett38",)),
"decred": (DCR_VERSION, DCR_VERSION_TAG, ("decred_release",)), "decred": (DCR_VERSION, DCR_VERSION_TAG, ("decred_release",)),
"namecoin": ("0.18.0", "", ("JeremyRand",)), "namecoin": (NMC_VERSION, NMC_VERSION_TAG, ("RoseTuring",)),
"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",)),
"pivx": (PIVX_VERSION, PIVX_VERSION_TAG, ("fuzzbawls",)), "pivx": (PIVX_VERSION, PIVX_VERSION_TAG, ("fuzzbawls",)),
@@ -116,26 +119,32 @@ known_coins = {
disabled_coins = [ disabled_coins = [
"navcoin", "navcoin",
"namecoin", # Needs update
] ]
expected_key_ids = { expected_key_ids = {
"tecnovert": ("13F13651C9CF0D6B",), "tecnovert": ("8E517DC12EC1CC37F6423A8A13F13651C9CF0D6B",),
"thrasher": ("FE3348877809386C",), "thrasher": ("59CAF0E96F23F53747945FD4FE3348877809386C",),
"laanwj": ("1E4AED62986CD25D",), "laanwj": ("9DEAE0DC7063249FB05474681E4AED62986CD25D",),
"JeremyRand": ("2DBE339E29F6294C",), "RoseTuring": ("FD8366A807A99FA27FD9CCEA9FE3BFDDA6C53495",),
"binaryfate": ("F0AF4D462A0BDF92",), "binaryfate": ("81AC591FE9C4B65C5806AFC3F0AF4D462A0BDF92",),
"wowario": ("793504B449C69220",), "wowario": ("AB3A2F725818FCFF2794841C793504B449C69220",),
"davidburkett38": ("3620E9D387E55666",), "davidburkett38": ("D35621D53A1CC6A3456758D03620E9D387E55666",),
"xanimo": ("6E8F17C1B1BCDCBE",), "xanimo": ("2EAA8B1021C71AD5186CA07F6E8F17C1B1BCDCBE",),
"patricklodder": ("2D3A345B98D0DC1F",), "patricklodder": ("DC6EF4A8BF9F1B1E4DE1EE522D3A345B98D0DC1F",),
"fuzzbawls": ("C1ABA64407731FD9",), "fuzzbawls": ("0CFBDA9F60D661BA31EB5D50C1ABA64407731FD9",),
"pasta": ("52527BEDABE87984", "E2F3D7916E722D38"), "pasta": (
"reuben": ("1290A1D0FA7EE109",), "29590362EC878A81FD3C202B52527BEDABE87984",
"nav_builder": ("2782262BF6E7FADB",), "02B8E7D002167C8B451AF05FE2F3D7916E722D38",
"nicolasdorier": ("6618763EF09186FE", "223FDA69DEBEA82D", "62FE85647DEDDA2E"), ),
"decred_release": ("6D897EDF518A031D",), "reuben": ("0186454D63E83D85EF91DE4E1290A1D0FA7EE109",),
"Calin_Culianu": ("21810A542031C02C",), "nav_builder": ("1BF9B51BAED51BA0B3A174EE2782262BF6E7FADB",),
"nicolasdorier": (
"AB4CFA9895ACA0DBE27F6B346618763EF09186FE",
"015B4C837B245509E4AC8995223FDA69DEBEA82D",
"7121BDE3555D9BE06BDDC68162FE85647DEDDA2E",
),
"decred_release": ("F516ADB7A069852C7C28A02D6D897EDF518A031D",),
"Calin_Culianu": ("D465135F97D0047E18E99DC321810A542031C02C",),
} }
USE_PLATFORM = os.getenv("USE_PLATFORM", platform.system()) USE_PLATFORM = os.getenv("USE_PLATFORM", platform.system())
@@ -181,6 +190,36 @@ PART_ONION_PORT = int(os.getenv("PART_ONION_PORT", 51734))
PART_RPC_USER = os.getenv("PART_RPC_USER", "") PART_RPC_USER = os.getenv("PART_RPC_USER", "")
PART_RPC_PWD = os.getenv("PART_RPC_PWD", "") PART_RPC_PWD = os.getenv("PART_RPC_PWD", "")
BTC_RPC_HOST = os.getenv("BTC_RPC_HOST", "127.0.0.1")
BTC_RPC_PORT = int(os.getenv("BTC_RPC_PORT", 19996))
BTC_PORT = int(os.getenv("BTC_PORT", 8333))
BTC_ONION_PORT = int(os.getenv("BTC_ONION_PORT", 8334))
BTC_RPC_USER = os.getenv("BTC_RPC_USER", "")
BTC_RPC_PWD = os.getenv("BTC_RPC_PWD", "")
LTC_RPC_HOST = os.getenv("LTC_RPC_HOST", "127.0.0.1")
LTC_RPC_PORT = int(os.getenv("LTC_RPC_PORT", 19895))
LTC_ONION_PORT = int(os.getenv("LTC_ONION_PORT", 9333))
LTC_RPC_USER = os.getenv("LTC_RPC_USER", "")
LTC_RPC_PWD = os.getenv("LTC_RPC_PWD", "")
DCR_RPC_HOST = os.getenv("DCR_RPC_HOST", "127.0.0.1")
DCR_RPC_PORT = int(os.getenv("DCR_RPC_PORT", 9109))
DCR_WALLET_RPC_HOST = os.getenv("DCR_WALLET_RPC_HOST", "127.0.0.1")
DCR_WALLET_RPC_PORT = int(os.getenv("DCR_WALLET_RPC_PORT", 9209))
DCR_WALLET_PWD = os.getenv(
"DCR_WALLET_PWD", random.randbytes(random.randint(14, 18)).hex()
)
DCR_RPC_USER = os.getenv("DCR_RPC_USER", "user")
DCR_RPC_PWD = os.getenv("DCR_RPC_PWD", random.randbytes(random.randint(14, 18)).hex())
NMC_RPC_HOST = os.getenv("NMC_RPC_HOST", "127.0.0.1")
NMC_RPC_PORT = int(os.getenv("NMC_RPC_PORT", 19698))
NMC_PORT = int(os.getenv("NMC_PORT", 8134))
NMC_ONION_PORT = int(os.getenv("NMC_ONION_PORT", 9698))
NMC_RPC_USER = os.getenv("NMC_RPC_USER", "")
NMC_RPC_PWD = os.getenv("NMC_RPC_PWD", "")
XMR_RPC_HOST = os.getenv("XMR_RPC_HOST", "127.0.0.1") XMR_RPC_HOST = os.getenv("XMR_RPC_HOST", "127.0.0.1")
XMR_RPC_PORT = int(os.getenv("XMR_RPC_PORT", 29798)) XMR_RPC_PORT = int(os.getenv("XMR_RPC_PORT", 29798))
XMR_ZMQ_PORT = int(os.getenv("XMR_ZMQ_PORT", 30898)) XMR_ZMQ_PORT = int(os.getenv("XMR_ZMQ_PORT", 30898))
@@ -203,32 +242,6 @@ WOW_RPC_USER = os.getenv("WOW_RPC_USER", "")
WOW_RPC_PWD = os.getenv("WOW_RPC_PWD", "") WOW_RPC_PWD = os.getenv("WOW_RPC_PWD", "")
DEFAULT_WOW_RESTORE_HEIGHT = int(os.getenv("DEFAULT_WOW_RESTORE_HEIGHT", 450000)) DEFAULT_WOW_RESTORE_HEIGHT = int(os.getenv("DEFAULT_WOW_RESTORE_HEIGHT", 450000))
LTC_RPC_HOST = os.getenv("LTC_RPC_HOST", "127.0.0.1")
LTC_RPC_PORT = int(os.getenv("LTC_RPC_PORT", 19895))
LTC_ONION_PORT = int(os.getenv("LTC_ONION_PORT", 9333))
LTC_RPC_USER = os.getenv("LTC_RPC_USER", "")
LTC_RPC_PWD = os.getenv("LTC_RPC_PWD", "")
BTC_RPC_HOST = os.getenv("BTC_RPC_HOST", "127.0.0.1")
BTC_RPC_PORT = int(os.getenv("BTC_RPC_PORT", 19996))
BTC_PORT = int(os.getenv("BTC_PORT", 8333))
BTC_ONION_PORT = int(os.getenv("BTC_ONION_PORT", 8334))
BTC_RPC_USER = os.getenv("BTC_RPC_USER", "")
BTC_RPC_PWD = os.getenv("BTC_RPC_PWD", "")
DCR_RPC_HOST = os.getenv("DCR_RPC_HOST", "127.0.0.1")
DCR_RPC_PORT = int(os.getenv("DCR_RPC_PORT", 9109))
DCR_WALLET_RPC_HOST = os.getenv("DCR_WALLET_RPC_HOST", "127.0.0.1")
DCR_WALLET_RPC_PORT = int(os.getenv("DCR_WALLET_RPC_PORT", 9209))
DCR_WALLET_PWD = os.getenv(
"DCR_WALLET_PWD", random.randbytes(random.randint(14, 18)).hex()
)
DCR_RPC_USER = os.getenv("DCR_RPC_USER", "user")
DCR_RPC_PWD = os.getenv("DCR_RPC_PWD", random.randbytes(random.randint(14, 18)).hex())
NMC_RPC_HOST = os.getenv("NMC_RPC_HOST", "127.0.0.1")
NMC_RPC_PORT = int(os.getenv("NMC_RPC_PORT", 19698))
PIVX_RPC_HOST = os.getenv("PIVX_RPC_HOST", "127.0.0.1") PIVX_RPC_HOST = os.getenv("PIVX_RPC_HOST", "127.0.0.1")
PIVX_RPC_PORT = int(os.getenv("PIVX_RPC_PORT", 51473)) PIVX_RPC_PORT = int(os.getenv("PIVX_RPC_PORT", 51473))
PIVX_ONION_PORT = int(os.getenv("PIVX_ONION_PORT", 51472)) # nDefaultPort PIVX_ONION_PORT = int(os.getenv("PIVX_ONION_PORT", 51472)) # nDefaultPort
@@ -375,6 +388,12 @@ def getWalletName(coin_params: str, default_name: str, prefix_override=None) ->
return wallet_name return wallet_name
def getDescriptorWalletOption(coin_params):
ticker: str = coin_params["ticker"]
default_option: bool = True if ticker in ("NMC",) else False
return toBool(os.getenv(ticker + "_USE_DESCRIPTORS", default_option))
def getKnownVersion(coin_name: str) -> str: def getKnownVersion(coin_name: str) -> str:
version, version_tag, _ = known_coins[coin_name] version, version_tag, _ = known_coins[coin_name]
return version + version_tag return version + version_tag
@@ -528,7 +547,7 @@ def testOnionLink():
def havePubkey(gpg, key_id): def havePubkey(gpg, key_id):
for key in gpg.list_keys(): for key in gpg.list_keys():
if key["keyid"] == key_id: if key["fingerprint"] == key_id:
return True return True
return False return False
@@ -591,8 +610,10 @@ def ensureValidSignatureBy(result, signing_key_name):
if not isValidSignature(result): if not isValidSignature(result):
raise ValueError("Signature verification failed.") raise ValueError("Signature verification failed.")
if result.key_id not in expected_key_ids[signing_key_name]: if result.fingerprint not in expected_key_ids[signing_key_name]:
raise ValueError("Signature made by unexpected keyid: " + result.key_id) raise ValueError(
"Signature made by unexpected key fingerprint: " + result.fingerprint
)
logger.debug(f"Found valid signature by {signing_key_name} ({result.key_id}).") logger.debug(f"Found valid signature by {signing_key_name} ({result.key_id}).")
@@ -931,16 +952,10 @@ def prepareCore(coin, version_data, settings, data_dir, extra_opts={}):
% (version, assert_filename) % (version, assert_filename)
) )
elif coin == "namecoin": elif coin == "namecoin":
release_url = "https://beta.namecoin.org/files/namecoin-core/namecoin-core-{}/{}".format( release_url = f"https://www.namecoin.org/files/namecoin-core/namecoin-core-{version}/{release_filename}"
version, release_filename signing_key = "Rose%20Turing"
) assert_filename = "noncodesigned.SHA256SUMS"
assert_filename = "{}-{}-{}-build.assert".format( assert_url = f"https://raw.githubusercontent.com/namecoin/guix.sigs/main/{version}/{signing_key}/{assert_filename}"
coin, os_name, version.rsplit(".", 1)[0]
)
assert_url = (
"https://raw.githubusercontent.com/namecoin/gitian.sigs/master/%s-%s/%s/%s"
% (version, os_dir_name, signing_key_name, assert_filename)
)
elif coin == "pivx": elif coin == "pivx":
release_filename = "{}-{}-{}.{}".format(coin, version, BIN_ARCH, FILE_EXT) release_filename = "{}-{}-{}.{}".format(coin, version, BIN_ARCH, FILE_EXT)
release_url = ( release_url = (
@@ -1345,6 +1360,8 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic, extra_opts={}):
fp.write("printtoconsole=0\n") fp.write("printtoconsole=0\n")
fp.write("daemon=0\n") fp.write("daemon=0\n")
fp.write(f"wallet={wallet_name}\n") fp.write(f"wallet={wallet_name}\n")
if "watch_wallet_name" in core_settings:
fp.write("wallet={}\n".format(core_settings["watch_wallet_name"]))
if tor_control_password is not None: if tor_control_password is not None:
writeTorSettings(fp, coin, core_settings, tor_control_password) writeTorSettings(fp, coin, core_settings, tor_control_password)
@@ -1401,6 +1418,10 @@ def prepareDataDir(coin, settings, chain, particl_mnemonic, extra_opts={}):
) )
elif coin == "namecoin": elif coin == "namecoin":
fp.write("prune=2000\n") fp.write("prune=2000\n")
fp.write("deprecatedrpc=create_bdb\n")
fp.write("addresstype=bech32\n")
fp.write("changetype=bech32\n")
fp.write("fallbackfee=0.001\n") # minrelaytxfee
elif coin == "pivx": elif coin == "pivx":
params_dir = os.path.join(data_dir, "pivx-params") params_dir = os.path.join(data_dir, "pivx-params")
downloadPIVXParams(params_dir) downloadPIVXParams(params_dir)
@@ -1804,6 +1825,7 @@ def initialise_wallets(
Coins.DOGE, Coins.DOGE,
Coins.DCR, Coins.DCR,
Coins.DASH, Coins.DASH,
Coins.NMC,
) )
# Always start Particl, it must be running to initialise a wallet in addcoin mode # Always start Particl, it must be running to initialise a wallet in addcoin mode
# Particl must be loaded first as subsequent coins are initialised from the Particl mnemonic # Particl must be loaded first as subsequent coins are initialised from the Particl mnemonic
@@ -1909,7 +1931,7 @@ def initialise_wallets(
f'Creating wallet "{wallet_name}" for {getCoinName(c)}.' f'Creating wallet "{wallet_name}" for {getCoinName(c)}.'
) )
if c in (Coins.BTC, Coins.LTC, Coins.DOGE, Coins.DASH): if c in (Coins.BTC, Coins.LTC, Coins.NMC, Coins.DOGE, Coins.DASH):
# wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors # wallet_name, disable_private_keys, blank, passphrase, avoid_reuse, descriptors
use_descriptors = coin_settings.get("use_descriptors", False) use_descriptors = coin_settings.get("use_descriptors", False)
@@ -1926,11 +1948,15 @@ def initialise_wallets(
], ],
) )
if use_descriptors: if use_descriptors:
watch_wallet_name = coin_settings["watch_wallet_name"]
logger.info(
f'Creating wallet "{watch_wallet_name}" for {getCoinName(c)}.'
)
swap_client.callcoinrpc( swap_client.callcoinrpc(
c, c,
"createwallet", "createwallet",
[ [
coin_settings["watch_wallet_name"], watch_wallet_name,
True, True,
True, True,
"", "",
@@ -2073,7 +2099,10 @@ def check_btc_fastsync_data(base_dir, sync_filename):
importPubkey(gpg, pubkey_filename, pubkeyurls) importPubkey(gpg, pubkey_filename, pubkeyurls)
with open(asc_file_path, "rb") as fp: with open(asc_file_path, "rb") as fp:
verified = gpg.verify_file(fp) verified = gpg.verify_file(fp)
if isValidSignature(verified) and verified.key_id in expected_key_ids["tecnovert"]: if (
isValidSignature(verified)
and verified.fingerprint in expected_key_ids["tecnovert"]
):
ensureValidSignatureBy(verified, "tecnovert") ensureValidSignatureBy(verified, "tecnovert")
else: else:
pubkey_filename = "nicolasdorier.asc" pubkey_filename = "nicolasdorier.asc"
@@ -2379,22 +2408,6 @@ def main():
"core_version_no": getKnownVersion("bitcoin"), "core_version_no": getKnownVersion("bitcoin"),
"core_version_group": 28, "core_version_group": 28,
}, },
"bitcoincash": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("BCH"),
"rpchost": BCH_RPC_HOST,
"rpcport": BCH_RPC_PORT + port_offset,
"onionport": BCH_ONION_PORT + port_offset,
"datadir": os.getenv("BCH_DATA_DIR", os.path.join(data_dir, "bitcoincash")),
"bindir": os.path.join(bin_dir, "bitcoincash"),
"port": BCH_PORT + port_offset,
"config_filename": "bitcoin.conf",
"use_segwit": False,
"blocks_confirmed": 1,
"conf_target": 2,
"core_version_no": getKnownVersion("bitcoincash"),
"core_version_group": 22,
},
"litecoin": { "litecoin": {
"connection_type": "rpc", "connection_type": "rpc",
"manage_daemon": shouldManageDaemon("LTC"), "manage_daemon": shouldManageDaemon("LTC"),
@@ -2410,22 +2423,6 @@ def main():
"core_version_group": 20, "core_version_group": 20,
"min_relay_fee": 0.00001, "min_relay_fee": 0.00001,
}, },
"dogecoin": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("DOGE"),
"rpchost": DOGE_RPC_HOST,
"rpcport": DOGE_RPC_PORT + port_offset,
"onionport": DOGE_ONION_PORT + port_offset,
"datadir": os.getenv("DOGE_DATA_DIR", os.path.join(data_dir, "dogecoin")),
"bindir": os.path.join(bin_dir, "dogecoin"),
"use_segwit": False,
"use_csv": False,
"blocks_confirmed": 2,
"conf_target": 2,
"core_version_no": getKnownVersion("dogecoin"),
"core_version_group": 23,
"min_relay_fee": 0.01, # RECOMMENDED_MIN_TX_FEE
},
"decred": { "decred": {
"connection_type": "rpc", "connection_type": "rpc",
"manage_daemon": shouldManageDaemon("DCR"), "manage_daemon": shouldManageDaemon("DCR"),
@@ -2453,14 +2450,16 @@ def main():
"manage_daemon": shouldManageDaemon("NMC"), "manage_daemon": shouldManageDaemon("NMC"),
"rpchost": NMC_RPC_HOST, "rpchost": NMC_RPC_HOST,
"rpcport": NMC_RPC_PORT + port_offset, "rpcport": NMC_RPC_PORT + port_offset,
"onionport": NMC_ONION_PORT + port_offset,
"datadir": os.getenv("NMC_DATA_DIR", os.path.join(data_dir, "namecoin")), "datadir": os.getenv("NMC_DATA_DIR", os.path.join(data_dir, "namecoin")),
"bindir": os.path.join(bin_dir, "namecoin"), "bindir": os.path.join(bin_dir, "namecoin"),
"use_segwit": False, "port": NMC_PORT + port_offset,
"use_csv": False, "use_segwit": True,
"use_csv": True,
"blocks_confirmed": 1, "blocks_confirmed": 1,
"conf_target": 2, "conf_target": 2,
"core_version_no": getKnownVersion("namecoin"), "core_version_no": getKnownVersion("namecoin"),
"core_version_group": 18, "core_version_group": 28,
"chain_lookups": "local", "chain_lookups": "local",
}, },
"monero": { "monero": {
@@ -2486,6 +2485,28 @@ def main():
"core_version_no": getKnownVersion("monero"), "core_version_no": getKnownVersion("monero"),
"core_type_group": "xmr", "core_type_group": "xmr",
}, },
"wownero": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("WOW"),
"manage_wallet_daemon": shouldManageDaemon("WOW_WALLET"),
"rpcport": WOW_RPC_PORT + port_offset,
"zmqport": WOW_ZMQ_PORT + port_offset,
"walletrpcport": WOW_WALLET_RPC_PORT + port_offset,
"rpchost": WOW_RPC_HOST,
"trusted_daemon": extra_opts.get("trust_remote_node", "auto"),
"walletrpchost": WOW_WALLET_RPC_HOST,
"walletrpcuser": WOW_WALLET_RPC_USER,
"walletrpcpassword": WOW_WALLET_RPC_PWD,
"datadir": os.getenv("WOW_DATA_DIR", os.path.join(data_dir, "wownero")),
"bindir": os.path.join(bin_dir, "wownero"),
"restore_height": wow_restore_height,
"blocks_confirmed": 2,
"rpctimeout": 60,
"walletrpctimeout": 120,
"walletrpctimeoutlong": 300,
"core_version_no": getKnownVersion("wownero"),
"core_type_group": "xmr",
},
"pivx": { "pivx": {
"connection_type": "rpc", "connection_type": "rpc",
"manage_daemon": shouldManageDaemon("PIVX"), "manage_daemon": shouldManageDaemon("PIVX"),
@@ -2549,27 +2570,37 @@ def main():
"chain_lookups": "local", "chain_lookups": "local",
"startup_tries": 40, "startup_tries": 40,
}, },
"wownero": { "bitcoincash": {
"connection_type": "rpc", "connection_type": "rpc",
"manage_daemon": shouldManageDaemon("WOW"), "manage_daemon": shouldManageDaemon("BCH"),
"manage_wallet_daemon": shouldManageDaemon("WOW_WALLET"), "rpchost": BCH_RPC_HOST,
"rpcport": WOW_RPC_PORT + port_offset, "rpcport": BCH_RPC_PORT + port_offset,
"zmqport": WOW_ZMQ_PORT + port_offset, "onionport": BCH_ONION_PORT + port_offset,
"walletrpcport": WOW_WALLET_RPC_PORT + port_offset, "datadir": os.getenv("BCH_DATA_DIR", os.path.join(data_dir, "bitcoincash")),
"rpchost": WOW_RPC_HOST, "bindir": os.path.join(bin_dir, "bitcoincash"),
"trusted_daemon": extra_opts.get("trust_remote_node", "auto"), "port": BCH_PORT + port_offset,
"walletrpchost": WOW_WALLET_RPC_HOST, "config_filename": "bitcoin.conf",
"walletrpcuser": WOW_WALLET_RPC_USER, "use_segwit": False,
"walletrpcpassword": WOW_WALLET_RPC_PWD, "blocks_confirmed": 1,
"datadir": os.getenv("WOW_DATA_DIR", os.path.join(data_dir, "wownero")), "conf_target": 2,
"bindir": os.path.join(bin_dir, "wownero"), "core_version_no": getKnownVersion("bitcoincash"),
"restore_height": wow_restore_height, "core_version_group": 22,
},
"dogecoin": {
"connection_type": "rpc",
"manage_daemon": shouldManageDaemon("DOGE"),
"rpchost": DOGE_RPC_HOST,
"rpcport": DOGE_RPC_PORT + port_offset,
"onionport": DOGE_ONION_PORT + port_offset,
"datadir": os.getenv("DOGE_DATA_DIR", os.path.join(data_dir, "dogecoin")),
"bindir": os.path.join(bin_dir, "dogecoin"),
"use_segwit": False,
"use_csv": False,
"blocks_confirmed": 2, "blocks_confirmed": 2,
"rpctimeout": 60, "conf_target": 2,
"walletrpctimeout": 120, "core_version_no": getKnownVersion("dogecoin"),
"walletrpctimeoutlong": 300, "core_version_group": 23,
"core_version_no": getKnownVersion("wownero"), "min_relay_fee": 0.01, # RECOMMENDED_MIN_TX_FEE
"core_type_group": "xmr",
}, },
} }
@@ -2593,9 +2624,8 @@ def main():
coin_settings["wallet_name"] = set_name coin_settings["wallet_name"] = set_name
ticker: str = coin_params["ticker"] ticker: str = coin_params["ticker"]
if toBool(os.getenv(ticker + "_USE_DESCRIPTORS", False)): if getDescriptorWalletOption(coin_params):
if coin_id not in (Coins.BTC, Coins.NMC):
if coin_id not in (Coins.BTC,):
raise ValueError(f"Descriptor wallet unavailable for {coin_name}") raise ValueError(f"Descriptor wallet unavailable for {coin_name}")
coin_settings["use_descriptors"] = True coin_settings["use_descriptors"] = True

View File

@@ -265,7 +265,11 @@ def getCoreBinArgs(coin_id: int, coin_settings, prepare=False, use_tor_proxy=Fal
# As BCH may use port 8334, disable it here. # As BCH may use port 8334, disable it here.
# When tor is enabled a bind option for the onionport will be added to bitcoin.conf. # When tor is enabled a bind option for the onionport will be added to bitcoin.conf.
# https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-28.0.md?plain=1#L84 # https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-28.0.md?plain=1#L84
if prepare is False and use_tor_proxy is False and coin_id == Coins.BTC: if (
prepare is False
and use_tor_proxy is False
and coin_id in (Coins.BTC, Coins.NMC)
):
port: int = coin_settings.get("port", 8333) port: int = coin_settings.get("port", 8333)
extra_args.append(f"--bind=0.0.0.0:{port}") extra_args.append(f"--bind=0.0.0.0:{port}")
return extra_args return extra_args

View File

@@ -58,6 +58,8 @@ chainparams = {
"bip44": 44, "bip44": 44,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0x696E82D1,
"ext_secret_key_prefix": 0x8F1DAEB8,
}, },
"testnet": { "testnet": {
"rpcport": 51935, "rpcport": 51935,
@@ -69,6 +71,8 @@ chainparams = {
"bip44": 1, "bip44": 1,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0xE1427800,
"ext_secret_key_prefix": 0x04889478,
}, },
"regtest": { "regtest": {
"rpcport": 51936, "rpcport": 51936,
@@ -80,6 +84,8 @@ chainparams = {
"bip44": 1, "bip44": 1,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0xE1427800,
"ext_secret_key_prefix": 0x04889478,
}, },
}, },
Coins.BTC: { Coins.BTC: {
@@ -251,29 +257,38 @@ chainparams = {
"rpcport": 8336, "rpcport": 8336,
"pubkey_address": 52, "pubkey_address": 52,
"script_address": 13, "script_address": 13,
"key_prefix": 180,
"hrp": "nc", "hrp": "nc",
"bip44": 7, "bip44": 7,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0x0488B21E, # base58Prefixes[EXT_PUBLIC_KEY]
"ext_secret_key_prefix": 0x0488ADE4,
}, },
"testnet": { "testnet": {
"rpcport": 18336, "rpcport": 18336,
"pubkey_address": 111, "pubkey_address": 111,
"script_address": 196, "script_address": 196,
"key_prefix": 239,
"hrp": "tn", "hrp": "tn",
"bip44": 1, "bip44": 1,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"name": "testnet3", "name": "testnet3",
"ext_public_key_prefix": 0x043587CF,
"ext_secret_key_prefix": 0x04358394,
}, },
"regtest": { "regtest": {
"rpcport": 18443, "rpcport": 18443,
"pubkey_address": 111, "pubkey_address": 111,
"script_address": 196, "script_address": 196,
"key_prefix": 239,
"hrp": "ncrt", "hrp": "ncrt",
"bip44": 1, "bip44": 1,
"min_amount": 100000, "min_amount": 100000,
"max_amount": 10000000 * COIN, "max_amount": 10000000 * COIN,
"ext_public_key_prefix": 0x043587CF,
"ext_secret_key_prefix": 0x04358394,
}, },
}, },
Coins.XMR: { Coins.XMR: {

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2019-2024 The Basicswap developers # Copyright (c) 2019-2025 The Basicswap developers
# 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.
@@ -40,13 +40,6 @@ DOGECOIND = os.getenv("DOGECOIND", "dogecoind" + bin_suffix)
DOGECOIN_CLI = os.getenv("DOGECOIN_CLI", "dogecoin-cli" + bin_suffix) DOGECOIN_CLI = os.getenv("DOGECOIN_CLI", "dogecoin-cli" + bin_suffix)
DOGECOIN_TX = os.getenv("DOGECOIN_TX", "dogecoin-tx" + bin_suffix) DOGECOIN_TX = os.getenv("DOGECOIN_TX", "dogecoin-tx" + bin_suffix)
NAMECOIN_BINDIR = os.path.expanduser(
os.getenv("NAMECOIN_BINDIR", os.path.join(DEFAULT_TEST_BINDIR, "namecoin"))
)
NAMECOIND = os.getenv("NAMECOIND", "namecoind" + bin_suffix)
NAMECOIN_CLI = os.getenv("NAMECOIN_CLI", "namecoin-cli" + bin_suffix)
NAMECOIN_TX = os.getenv("NAMECOIN_TX", "namecoin-tx" + bin_suffix)
XMR_BINDIR = os.path.expanduser( XMR_BINDIR = os.path.expanduser(
os.getenv("XMR_BINDIR", os.path.join(DEFAULT_TEST_BINDIR, "monero")) os.getenv("XMR_BINDIR", os.path.join(DEFAULT_TEST_BINDIR, "monero"))
) )

View File

@@ -1862,20 +1862,70 @@ class BTCInterface(Secp256k1Interface):
"Could not find address with enough funds for proof", "Could not find address with enough funds for proof",
) )
self._log.debug("sign_for_addr %s", sign_for_addr) self._log.debug(f"sign_for_addr {sign_for_addr}")
funds_addr: str = sign_for_addr
if ( if (
self.using_segwit() self.using_segwit()
): # TODO: Use isSegwitAddress when scantxoutset can use combo ): # TODO: Use isSegwitAddress when scantxoutset can use combo
# 'Address does not refer to key' for non p2pkh # 'Address does not refer to key' for non p2pkh
pkh = self.decodeAddress(sign_for_addr) pkh = self.decodeAddress(sign_for_addr)
sign_for_addr = self.pkh_to_address(pkh) sign_for_addr = self.pkh_to_address(pkh)
self._log.debug("sign_for_addr converted %s", sign_for_addr) self._log.debug(f"sign_for_addr converted {sign_for_addr}")
signature = self.rpc_wallet( if self._use_descriptors:
"signmessage", # https://github.com/bitcoin/bitcoin/issues/10542
[sign_for_addr, sign_for_addr + "_swap_proof_" + extra_commit_bytes.hex()], # https://github.com/bitcoin/bitcoin/issues/26046
) priv_keys = self.rpc_wallet(
"listdescriptors",
[
True,
],
)
addr_info = self.rpc_wallet(
"getaddressinfo",
[
funds_addr,
],
)
hdkeypath = addr_info["hdkeypath"]
sign_for_address_key = None
for descriptor in priv_keys["descriptors"]:
if descriptor["active"] is False or descriptor["internal"] is True:
continue
desc = descriptor["desc"]
assert desc.startswith("wpkh(")
ext_key = desc[5:].split(")")[0].split("/", 1)[0]
ext_key_data = decodeAddress(ext_key)[4:]
ci_part = self._sc.ci(Coins.PART)
ext_key_data_part = ci_part.encode_secret_extkey(ext_key_data)
rv = ci_part.rpc_wallet(
"extkey", ["info", ext_key_data_part, hdkeypath]
)
extkey_derived = rv["key_info"]["result"]
ext_key_data = decodeAddress(extkey_derived)[4:]
ek = ExtKeyPair()
ek.decode(ext_key_data)
sign_for_address_key = self.encodeKey(ek._key)
break
assert sign_for_address_key is not None
signature = self.rpc(
"signmessagewithprivkey",
[
sign_for_address_key,
sign_for_addr + "_swap_proof_" + extra_commit_bytes.hex(),
],
)
del priv_keys
else:
signature = self.rpc_wallet(
"signmessage",
[
sign_for_addr,
sign_for_addr + "_swap_proof_" + extra_commit_bytes.hex(),
],
)
prove_utxos = [] # TODO: Send specific utxos prove_utxos = [] # TODO: Send specific utxos
return (sign_for_addr, signature, prove_utxos) return (sign_for_addr, signature, prove_utxos)

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 tecnovert # Copyright (c) 2020-2022 tecnovert
# Copyright (c) 2025 The Basicswap developers
# 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.
@@ -13,39 +14,3 @@ class NMCInterface(BTCInterface):
@staticmethod @staticmethod
def coin_type(): def coin_type():
return Coins.NMC return Coins.NMC
def getLockTxHeight(
self,
txid,
dest_address,
bid_amount,
rescan_from,
find_index: bool = False,
vout: int = -1,
):
self._log.debug("[rm] scantxoutset start") # scantxoutset is slow
ro = self.rpc(
"scantxoutset", ["start", ["addr({})".format(dest_address)]]
) # TODO: Use combo(address) where possible
self._log.debug("[rm] scantxoutset end")
return_txid = True if txid is None else False
for o in ro["unspents"]:
if txid and o["txid"] != txid.hex():
continue
# Verify amount
if self.make_int(o["amount"]) != int(bid_amount):
self._log.warning(
"Found output to lock tx address of incorrect value: %s, %s",
str(o["amount"]),
o["txid"],
)
continue
rv = {"depth": 0, "height": o["height"]}
if o["height"] > 0:
rv["depth"] = ro["height"] - o["height"]
if find_index:
rv["index"] = o["vout"]
if return_txid:
rv["txid"] = o["txid"]
return rv

View File

@@ -0,0 +1,25 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQMuBFmZ6L4RCACuqDDCIe2bzKznyKVN1aInzRQnSxdGTXuw0mcDz5HYudAhBjR8
gY6sxCRPNxvZCJVDZDpCygXMhWZlJtWLR8KMTCXxC4HLXXOY4RxQ5KGnYWxEAcKY
deq1ymmuOuMUp7ltRTSyWcBKbR9xTd2vW/+0W7GQIOxUW/aiT1V0x3cky+6kqaec
BorP3+uxJcx0Q8WdlS/6N4x3pBv/lfsdrZSaDD8fU/29pQGMDUEnupKoWJVVei6r
G+vxLHEtIFYYO8VWjZntymw3dl+aogrjyuxqWzl8mfPi9M/DgiRb4pJnH2yOGDI6
Lvg+oo9E79Vwi98UjYSicsB1dtcptKiA96UXAQD/hDB+dil7/SX/SDTlaw/+uTdd
Xg0No63dbN++iY4k3Qf/Xk1ZzbuDviLhe+zEhlJOw6TaMlxfwwQOtxEJXILS5uIL
jYlGcDbBtJh3p4qUoUduDOgjumJ9m47XqIq81rQ0pqzzGMbK1Y82NQjX5Sn8yTm9
p1hmOZ/uX9vCrUSbYBjxJXyQ1OXlerlLRLfBf5WQ0+LO+0cmgtCyX0zV4oGK7vph
XEm7lar7AezOOXaSrWAB+CTPUdJF1E7lcJiUuMVcqMx8pphrH+rfcsqPtN6tkyUD
TmPDpc5ViqFFelEEQnKSlmAY+3iCNZ3y/VdPPhuJ2lAsL3tm9MMh2JGV378LG45a
6SOkQrC977Qq1dhgJA+PGJxQvL2RJWsYlJwp79+Npgf9EfFaJVNzbdjGVq1XmNie
MZYqHRfABkyK0ooDxSyzJrq4vvuhWKInS4JhpKSabgNSsNiiaoDR+YYMHb0H8GRR
Za6JCmfU8w97R41UTI32N7dhul4xCDs5OV6maOIoNts20oigNGb7TKH9b5N7sDJB
zh3Of/fHCChO9Y2chbzU0bERfcn+evrWBf/9XdQGQ3ggoLbOtGpcUQuB/7ofTcBZ
awL6K4VJ2Qlb8DPlRgju6uU9AR/KTYeAlVFC8FX7R0FGgPRcJ3GNkNHGqrbuQ72q
AOhYOPx9nRrU5u+E2J325vOabLnLbOazze3j6LFPSFV4vfmTO9exYlwhz3g+lFAd
CrQ2Q2FsaW4gQ3VsaWFudSAoTmlsYWNUaGVHcmltKSA8Y2FsaW4uY3VsaWFudUBn
bWFpbC5jb20+iHoEExEIACIFAlmZ6L4CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B
AheAAAoJECGBClQgMcAsU5cBAO/ngONpHsxny2uTV4ge2f+5V2ajTjcIfN2jUZtg
31jJAQCl1NcrwcIu98+aM2IyjB1UFXkoaMANpr8L9jBopivRGQ==
=cf8I
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,14 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEXPNfCBYJKwYBBAHaRw8BAQdAWGFiEJYnlV2TDTesLIO/eoQ3IPduzcG97GpA
6K+Gj+K0K0BKZXJlbXlSYW5kIG9uIEdpdEh1YiA8amVyZW15QG5hbWVjb2luLm9y
Zz6IlgQTFggAPhYhBJza8EpykDv+wJWdvi2+M54p9ilMBQJc88q7AhsDBQkB4TOA
BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEC2+M54p9ilMMUoA/1oZn8AtwQ7D
wXgNKq++zqHaiEcHGgsyFeDRbQARsYRVAQDxa36p181id1YuMjeV1KhC5vaDS4nY
GB4FHPsQ4bbqDLRESmVyZW15IFJhbmQgKE5hbWVjb2luIENvcmUgR2l0aWFuIFNp
Z25pbmcgS2V5KSA8amVyZW15QG5hbWVjb2luLm9yZz6ImQQTFggAQQIbAwUJAeEz
gAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBJza8EpykDv+wJWdvi2+M54p9ilM
BQJc9WDrAhkBAAoJEC2+M54p9ilMz3IA/3mCKeFYcEJFlwP43mdIMGOV2zt/R4Fn
z/rBJpv5hFoHAQDXAY8+mbY/9N+5Rn8Iy51tXEaTq3khdruuFFdty+bXAg==
=EpnJ
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=atlH
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,78 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFlLyDYBCADqup3EHjFCMELf4I0smf4hDl48qDn/Hue08JLmSToMc7z9ylLk mQINBFlLyYIBEADW3oJnVMDC94g+7OB1/IBUYNevCqJIOAtC0eeFS5g0XGvvqRLx
6Uzx6S1m7RiDO63A7yW4qyRkb54VNj+6rUSPNt2uVy1vT8OEQJAZLf2c4qpaKHAQ 2NLUqn5te+R7deoGElkZFJLLxFUwEnhqGCRH50Iou5aanUzvgI5fVAbK3k0fp9vc
QV3utu8pYxYOJfLHh4zNEGXrbSrjDv/FTPuri+SkIABhjf70ZSocm4l49rtBanK5 LKCR0fQVIidcLyqMpkLZo8BSE3+BWxFp/r2OHvh2dYtJC+BZVwblkDS3cqwKvUZx
AIAp8DoXWcUdbwmAfl6qrLfzrDu75kq+bspd8p4CVy4fzdOtr6LvXW38z1t3XtLP IocvDs47Wo3tzZfEsqUavbbiGx+Dm0fCV7TVHdVLU7q3bZsHSRiyTUZ2EAApoAmT
+EGVMAzZQWr2WbN762rK7skH+ZfhaMjAwr8gPYymYnFGLdS1nBmhksnulQNGQOro ir9csVxv2IM8yf6/HwWi6/Lp7dgSG1+qBZ1lUPPTY+dFLPZyt/kul+vuOj6GLZaU
WojsvQKgBJoGUnp/OrVpi3gn7UNfDo99CxMRABEBAAG0IHRlY25vdmVydCA8dGVj s3D66d7TaPCHKWAOnP9RHpic/iXODXVXo1KHJfa0x8fW7I+y7/Gb+5x/m4O0Bz2T
bm92ZXJ0QHBhcnRpY2wuaW8+iQFUBBMBCAA+FiEEOQGTZk5wi3vnahADcJ5tyVzr BivdrSAuFpXkPqwawlw4CPgI9fc801g83+ZFzD2jJ6qxkEgfnlmf+zGNn5tC4N5j
Ac8FAllLyDYCGwMFCQPCZwAFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQcJ5t NRTQ+GyHo1w4824SXcSN590wgz8goGJC3QPJxbifvOA8GzQIVzpxHckofOVyqIEq
yVzrAc+0LAf/SvBJFJGq1yT9pdLT+7lv7BrshfSYQBLNqPmPrxRuxzH3q/EaEk6D qSnkP2xn4mELqD7HcFnoojZBqFbF2cN+oWQ+niLN+v4qrUncpQI9SVWlyp66S+1T
oQh/Jk4vmSXR1y+bsKtS55ekGsPZZWlUFMbXDuU0II3YkWewHXTnqxLtqzcWODoK BhBQj2QuX+3B+K27EiDbhNV7EX6xEbGsnB1poMc2aMiz6veybW3GnoM+2ppr8Ko/
6vPonjiVuhYC57d4TWw5ebzHy8wICunyVeaL/cvYQM1TfaI2fN5v0Ep+XiRpH/15 12Ij7l+ZA44t6PWUfQQbNSbUk/0Yhd9QJ8VQVck+TaS6gtarTbURlSdmHwARAQAB
HQzRaynKq58w7gH79mPIRA2WFz4eMIMWS3rSa+cSoJ0MhpimgnKUDlh2DebVP1eH tCl0ZWNub3ZlcnQgKGdpdGlhbikgPHRlY25vdmVydEBwYXJ0aWNsLmlvPokCVAQT
keSW1JlPZHhca/XB93ghFlbO6wOrbg+gsKtB45OkpsoOzUMFIKVJLBAjK751dTcc AQgAPhYhBI5RfcEuwcw39kI6ihPxNlHJzw1rBQJZS8mCAhsDBQkSzAMABQsJCAcC
Pb4xTzABaBXxk+IUxgGB1h+g3i6wzksfgLkBDQRZS8g2AQgAw7Db3G5J21jsty9S BhUICQoLAgQWAgMBAh4BAheAAAoJEBPxNlHJzw1rtdYP/22iRX8O2Q++MayPHNx5
pMmqp93dgZFm8E4VTcsL4KVvZybhwHngNHnhG8G/DWQ53o07/BKorfRBmFD3x2Eq XHAlMk9mfi5FB1qJwshtlhda7P9U/hOTi227wH+Mzh5dBje4t2DkoHzxlz/Wr4cQ
RqfOn4ytmZVw/sOjbZPi4m/tF8z+O9qR8I0CzedYip21rwz2j4UgnpDQ+BnOpyXB QUJMOYd0OEZY6kpAQkvtyYobIb6zlRQK1koAfNMxewmfZZGTlr16IUVCovGSFvZ+
H0gDBlPFq8ih9kkm413QRTTKnkRM/U8SfyFU8vIFdH7T0Ae07m0LxePDaTyxLPg3 hdYRDEjuHqXjpwBfrxFAy/HCnfY10qSRkJc5w1ypj1IkzlanS+xeRJSDvRTQDAEr
x1+RvEjVkruc3/9Z4kzexoUv654wirRdxPX8GsWI1WNDQrj4GqmpF/e0WDM97+Lk zv3xKcMGjCCHaaCP+tyAaViBaUOlvmZdWwg0gwQCuPLqIh0cfDbcg0quciRIpnyp
DGzbcXy7TGMIHQx8QFlFwdSZv9x70574as9Od4jOWTk90sopSMr8t6H6wTdn+2MD zINmfwngZCwXdIYfAzmCzMHw1J3iOiqfqK0EcpHMsL689VyQSPgsoEHtcOGHYjRL
qsZKUwARAQABiQE8BBgBCAAmFiEEOQGTZk5wi3vnahADcJ5tyVzrAc8FAllLyDYC pMPGvRFHtICrnCHENK3IcwFWDGXW+i3zgOlA7g48yYWWvSup+t8I6YT+FeeFlxSO
GwwFCQPCZwAACgkQcJ5tyVzrAc/QFgf8CQydF/VqJtujQC/rjB1YYNQcljzoeQWA dj1GdeMA0O7gXZ7znLVduokL2Ef4dZjc+3NwBlFov52vwCZwQMAGsMriwEDB2rDZ
2F2O5cF5skTNYy+xas3PTgxfOpn5iTpixpkB+I7X8LwoPmRjZvg2MFirDVXUypcx B7YOvAxlUB/kavtx/oE8fV7mZcuwYg02lq4bozF9xlhjOFaRit6xXnLVi0TuI76c
HwMbQqYCuAaK1EhtVUVYbFGjM67nClmBApLdenbqEP/BhyR9kgDCBt7ZvSLe5N/6 uz67nB9VkWczSLIzCyjNyFpWbx1BMxTYfehZX3+YNajXwG6HdEp9CAYK0u46Guz/
MKYJF1FlCgGc5OJPJrMIl0slU5QtzRy5J+l75WflkgxFUKJPotJ5Z+yduxOff//e Pth67bbNVYyP/cuOIrv/hqQ6xo4mOBMDDxcCEAXx3rwxfbxNM8vlwrMcpITrtNON
qSEXqlkaebWT0ZFiAqHhExJCRJ5HBqQEdW4JHrB7j3bNh8Qdf8epiYtcXXSsE9+K r41bcxUIfMEDefPm5wnXep8W
XEP7UJRk5bFFKdn0wMONgmQLMjjspU5byMQDJ0hFNMmmrbKX2AXqRpkCDQRZS8mC =szpX
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
XHovfCfpcB/C
=0Wkp
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGROehcBEACXWWc6dHqCos1PmKI32iHi0jP3mYM3jU57YxbjwT78QEtEwSqf
YklpXkgTYq7jexx2JElfegM6w1sPYarq1y051RjnCgzl32da5I506SMvcJTmXumV
Rw6erPeDxAO74PflDSlALgtGOgbKhwwWRudbWgT5hKGkl62qy0mI6GStul0rbT+3
gq77DCGyURfe1PG1pymhO5XVz3WGtOa12NvRA+3wGIcqIji2MbtXuOhGMg//kVI5
m2vcfHyMMuQ01xUXRu57WxRujYaJ1RB4p86JCbDX3YU2XlzTxGAhqChDLuJGqo54
AZMUWDceftXsAoOqH8Hwmm5gFkYSpMt86ZT+umvWygmxohD5k85MuRj4AGagFj/u
CMcQjI/SN1UU/Qozg6VL/5FO8aH9IybDzX7eE3j0V/jTweStw1CIUajYgfemWOWl
whLPBDflRz/8EEqTN0CaSSaiYiULZUiawBO/bRIiCO2Q6QrAi3KpPUhCwiw/Yecd
rAMLH7bytpECDdbNonQ/VMxWwtWJQ87qBtWvHFQxXBKjyuANsKL9X7v3KcYOUdd2
fSt7eqE9GDT4DbK6sTmuTpq2TgHXET0cA39+N2zxTh5xFupI/pi2iAHJ6hgIiQnn
662TngjGOSFvrTV/51Ua0Vx8OCMJJOcRdOVaYzuzg9DsjVcJin3aRqUh4wARAQAB
tCBXb3dhcmlvIDx3b3dhcmlvQHByb3Rvbm1haWwuY29tPokCVAQTAQgAPhYhBKs6
L3JYGPz/J5SEHHk1BLRJxpIgBQJkTnoXAhsDBQkHhh77BQsJCAcCBhUKCQgLAgQW
AgMBAh4BAheAAAoJEHk1BLRJxpIgwgEP/109vw1WXRh9EaRr3Y1+sBi+/PRQ5TCx
UEcP9ru5sQPJ0BsZK8RYw0BNIfDQX9OB1k/AoiBelL+0EoDKvjXmwz9fPUmSVk5r
3RzfClXTnxn4HXPKkSGMt4WBUnvohTexK7CPkb9xy+K0Jtx8XF1XiQLDFg2a9lBj
IIX2H6aHn4VjdUBv7TrTCAI2Vg0cQUpeJUwyHH+lk0r2WM3zAxzS3Iy2yDDstNT8
audXEX4BtJhyEU1m57jwgscrbTtgwYOAsaRLcnUaAFWhbov3IiGInk7N1fkMsuW5
HE5RcegSZRS3X4o6O/nmwdSjCEB9weydOCPrtfdbvfvuTiMg/jZBikOk/Sj7FM/D
eZKghSHpLbT/V3S76FyIcc/xFkUmR+2fGvCNjJ1Qn2lXTS8xcbyzqR4LZPeUGppV
hvriilLnXSjyc60wuD3kmCCo1Zw4tNL8pr09BtVmScUy6eiwca8LLzvbbivqxF1g
Mrkkv8yQE0ZwO1kgNSn+PSzUPbwAoklcyN5Rhr5DxZh0UudiH5Jt5WWYeE8O2Uc1
si13X575kymGkkeiUcp9WtBkh2uial+RVmTrUTDUTIR2HzT6MAR84/DHlC5dsW8a
h4uDUhzeG2cTxuIfZC881UHKL+xT/I3PPuFdLbU5uoWJpXYpxKYulYWd7LA/k4bi
JWBrQo7VDvvP
=H3wS
-----END PGP PUBLIC KEY BLOCK-----

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -10,6 +10,7 @@ const COIN_NAME_TO_SYMBOL = {
'Firo': 'FIRO', 'Firo': 'FIRO',
'Dash': 'DASH', 'Dash': 'DASH',
'Decred': 'DCR', 'Decred': 'DCR',
'Namecoin': 'NMC',
'Wownero': 'WOW', 'Wownero': 'WOW',
'Bitcoin Cash': 'BCH', 'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE' 'Dogecoin': 'DOGE'
@@ -383,7 +384,6 @@ const createBidTableRow = async (bid) => {
</div> </div>
</div> </div>
</td> </td>
<!-- You Get Column --> <!-- You Get Column -->
<td class="py-0"> <td class="py-0">
<div class="py-3 px-4 text-right"> <div class="py-3 px-4 text-right">

View File

@@ -220,7 +220,7 @@ const ApiManager = (function() {
.filter(coin => coin.usesCoinGecko) .filter(coin => coin.usesCoinGecko)
.map(coin => coin.name) .map(coin => coin.name)
.join(',') : .join(',') :
'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred'; 'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred,namecoin';
//console.log('Fetching coin prices for:', coins); //console.log('Fetching coin prices for:', coins);
const response = await this.fetchCoinPrices(coins); const response = await this.fetchCoinPrices(coins);
@@ -254,7 +254,7 @@ const ApiManager = (function() {
.filter(coin => coin.usesCoinGecko) .filter(coin => coin.usesCoinGecko)
.map(coin => getCoinBackendId ? getCoinBackendId(coin.name) : coin.name) .map(coin => getCoinBackendId ? getCoinBackendId(coin.name) : coin.name)
.join(',') : .join(',') :
'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred'; 'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred,namecoin';
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coins}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`; const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coins}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`;

View File

@@ -504,13 +504,14 @@ const CacheManager = (function() {
'bitcoin': 'BTC', 'bitcoin': 'BTC',
'litecoin': 'LTC', 'litecoin': 'LTC',
'monero': 'XMR', 'monero': 'XMR',
'wownero': 'WOW',
'particl': 'PART', 'particl': 'PART',
'pivx': 'PIVX', 'pivx': 'PIVX',
'firo': 'FIRO', 'firo': 'FIRO',
'zcoin': 'FIRO', 'zcoin': 'FIRO',
'dash': 'DASH', 'dash': 'DASH',
'decred': 'DCR', 'decred': 'DCR',
'wownero': 'WOW', 'namecoin': 'NMR',
'bitcoin-cash': 'BCH', 'bitcoin-cash': 'BCH',
'dogecoin': 'DOGE' 'dogecoin': 'DOGE'
}; };

View File

@@ -72,6 +72,7 @@ const ConfigManager = (function() {
{ symbol: 'LTC', name: 'litecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 }, { symbol: 'LTC', name: 'litecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'DOGE', name: 'dogecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 }, { symbol: 'DOGE', name: 'dogecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'DCR', name: 'decred', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 }, { symbol: 'DCR', name: 'decred', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'NMC', name: 'namecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
{ symbol: 'WOW', name: 'wownero', usesCryptoCompare: false, usesCoinGecko: true, historicalDays: 30 } { symbol: 'WOW', name: 'wownero', usesCryptoCompare: false, usesCoinGecko: true, historicalDays: 30 }
], ],
@@ -88,6 +89,7 @@ const ConfigManager = (function() {
'Zcoin': 'FIRO', 'Zcoin': 'FIRO',
'Dash': 'DASH', 'Dash': 'DASH',
'Decred': 'DCR', 'Decred': 'DCR',
'Namecoin': 'NMC',
'Wownero': 'WOW', 'Wownero': 'WOW',
'Bitcoin Cash': 'BCH', 'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE' 'Dogecoin': 'DOGE'
@@ -105,13 +107,14 @@ const ConfigManager = (function() {
'Zcoin': 'Firo', 'Zcoin': 'Firo',
'Dash': 'Dash', 'Dash': 'Dash',
'Decred': 'Decred', 'Decred': 'Decred',
'Namecoin': 'Namecoin',
'Wownero': 'Wownero', 'Wownero': 'Wownero',
'Bitcoin Cash': 'Bitcoin Cash', 'Bitcoin Cash': 'Bitcoin Cash',
'Dogecoin': 'Dogecoin' 'Dogecoin': 'Dogecoin'
}, },
idToName: { idToName: {
1: 'particl', 2: 'bitcoin', 3: 'litecoin', 4: 'decred', 1: 'particl', 2: 'bitcoin', 3: 'litecoin', 4: 'decred', 5: 'namecoin',
6: 'monero', 7: 'particl blind', 8: 'particl anon', 6: 'monero', 7: 'particl blind', 8: 'particl anon',
9: 'wownero', 11: 'pivx', 13: 'firo', 17: 'bitcoincash', 9: 'wownero', 11: 'pivx', 13: 'firo', 17: 'bitcoincash',
18: 'dogecoin' 18: 'dogecoin'
@@ -130,6 +133,7 @@ const ConfigManager = (function() {
'litecoin': 'litecoin', 'litecoin': 'litecoin',
'dogecoin': 'dogecoin', 'dogecoin': 'dogecoin',
'decred': 'decred', 'decred': 'decred',
'namecoin': 'namecoin',
'wownero': 'wownero' 'wownero': 'wownero'
} }
}, },
@@ -367,6 +371,7 @@ const ConfigManager = (function() {
'dash': { usd: null, btc: null }, 'dash': { usd: null, btc: null },
'dogecoin': { usd: null, btc: null }, 'dogecoin': { usd: null, btc: null },
'decred': { usd: null, btc: null }, 'decred': { usd: null, btc: null },
'namecoin': { usd: null, btc: null },
'litecoin': { usd: null, btc: null }, 'litecoin': { usd: null, btc: null },
'particl': { usd: null, btc: null }, 'particl': { usd: null, btc: null },
'pivx': { usd: null, btc: null }, 'pivx': { usd: null, btc: null },

View File

@@ -35,6 +35,7 @@ const WalletManager = (function() {
'Dash': 'DASH', 'Dash': 'DASH',
'PIVX': 'PIVX', 'PIVX': 'PIVX',
'Decred': 'DCR', 'Decred': 'DCR',
'Namecoin': 'NMC',
'Bitcoin Cash': 'BCH' 'Bitcoin Cash': 'BCH'
}, },
@@ -49,6 +50,7 @@ const WalletManager = (function() {
'DASH': 'dash', 'DASH': 'dash',
'PIVX': 'pivx', 'PIVX': 'pivx',
'DCR': 'dcr', 'DCR': 'dcr',
'NMC': 'nmc',
'BCH': 'bch' 'BCH': 'bch'
}, },
@@ -63,6 +65,7 @@ const WalletManager = (function() {
'Dash': 'DASH', 'Dash': 'DASH',
'PIVX': 'PIVX', 'PIVX': 'PIVX',
'Decred': 'DCR', 'Decred': 'DCR',
'Namecoin': 'NMC',
'Bitcoin Cash': 'BCH', 'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE' 'Dogecoin': 'DOGE'
} }

View File

@@ -34,6 +34,7 @@ window.tableRateModule = {
'Dash': 'DASH', 'Dash': 'DASH',
'PIVX': 'PIVX', 'PIVX': 'PIVX',
'Decred': 'DCR', 'Decred': 'DCR',
'Namecoin': 'NMC',
'Zano': 'ZANO', 'Zano': 'ZANO',
'Bitcoin Cash': 'BCH', 'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE' 'Dogecoin': 'DOGE'
@@ -306,6 +307,7 @@ async function calculateProfitLoss(fromCoin, toCoin, fromAmount, toAmount, isOwn
'ltc': 'litecoin', 'ltc': 'litecoin',
'doge': 'dogecoin', 'doge': 'dogecoin',
'dcr': 'decred', 'dcr': 'decred',
'nmc': 'namecoin',
'wow': 'wownero' 'wow': 'wownero'
}; };
@@ -406,7 +408,7 @@ async function fetchLatestPrices() {
const coinIds = [ const coinIds = [
'bitcoin', 'particl', 'monero', 'litecoin', 'bitcoin', 'particl', 'monero', 'litecoin',
'dogecoin', 'firo', 'dash', 'pivx', 'dogecoin', 'firo', 'dash', 'pivx',
'decred', 'bitcoincash' 'decred', 'namecoin', 'bitcoincash'
]; ];
let processedData = {}; let processedData = {};
@@ -1365,6 +1367,7 @@ function createRateColumn(offer, coinFrom, coinTo) {
'ltc': 'litecoin', 'ltc': 'litecoin',
'doge': 'dogecoin', 'doge': 'dogecoin',
'dcr': 'decred', 'dcr': 'decred',
'nmc': 'namecoin',
'wow': 'wownero' 'wow': 'wownero'
}; };
@@ -1655,6 +1658,7 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou
'ltc': 'litecoin', 'ltc': 'litecoin',
'doge': 'dogecoin', 'doge': 'dogecoin',
'dcr': 'decred', 'dcr': 'decred',
'nmc': 'namecoin',
'wow': 'wownero' 'wow': 'wownero'
}; };
@@ -1757,6 +1761,7 @@ function createCombinedRateTooltip(offer, coinFrom, coinTo, treatAsSentOffer) {
'ltc': 'litecoin', 'ltc': 'litecoin',
'doge': 'dogecoin', 'doge': 'dogecoin',
'dcr': 'decred', 'dcr': 'decred',
'nmc': 'namecoin',
'wow': 'wownero' 'wow': 'wownero'
}; };

View File

@@ -548,7 +548,7 @@ const ui = {
}, },
setActiveContainer: (containerId) => { setActiveContainer: (containerId) => {
const containerIds = ['btc', 'xmr', 'part', 'pivx', 'firo', 'dash', 'ltc', 'doge', 'eth', 'dcr', 'zano', 'wow', 'bch'].map(id => `${id}-container`); const containerIds = ['btc', 'xmr', 'part', 'pivx', 'firo', 'dash', 'ltc', 'doge', 'eth', 'dcr', 'nmc', 'zano', 'wow', 'bch'].map(id => `${id}-container`);
containerIds.forEach(id => { containerIds.forEach(id => {
const container = document.getElementById(id); const container = document.getElementById(id);
if (container) { if (container) {

View File

@@ -10,6 +10,7 @@ const COIN_NAME_TO_SYMBOL = {
'Firo': 'FIRO', 'Firo': 'FIRO',
'Dash': 'DASH', 'Dash': 'DASH',
'Decred': 'DCR', 'Decred': 'DCR',
'Namecoin': 'NMC',
'Wownero': 'WOW', 'Wownero': 'WOW',
'Bitcoin Cash': 'BCH', 'Bitcoin Cash': 'BCH',
'Dogecoin': 'DOGE' 'Dogecoin': 'DOGE'

View File

@@ -136,11 +136,12 @@
'ETH': {'name': 'Ethereum', 'symbol': 'ETH', 'image': 'Ethereum.png', 'show': false}, 'ETH': {'name': 'Ethereum', 'symbol': 'ETH', 'image': 'Ethereum.png', 'show': false},
'DOGE': {'name': 'Dogecoin', 'symbol': 'DOGE', 'image': 'Dogecoin.png', 'show': true}, 'DOGE': {'name': 'Dogecoin', 'symbol': 'DOGE', 'image': 'Dogecoin.png', 'show': true},
'DCR': {'name': 'Decred', 'symbol': 'DCR', 'image': 'Decred.png', 'show': true}, 'DCR': {'name': 'Decred', 'symbol': 'DCR', 'image': 'Decred.png', 'show': true},
'NMC': {'name': 'Namecoin', 'symbol': 'NMC', 'image': 'Namecoin.png', 'show': true},
'ZANO': {'name': 'Zano', 'symbol': 'ZANO', 'image': 'Zano.png', 'show': false}, 'ZANO': {'name': 'Zano', 'symbol': 'ZANO', 'image': 'Zano.png', 'show': false},
'WOW': {'name': 'Wownero', 'symbol': 'WOW', 'image': 'Wownero.png', 'show': true} 'WOW': {'name': 'Wownero', 'symbol': 'WOW', 'image': 'Wownero.png', 'show': true}
} }
%} %}
{% set custom_order = ['BTC', 'ETH', 'XMR', 'PART', 'LTC', 'BCH', 'FIRO', 'PIVX', 'DASH', 'DOGE', 'DCR', 'ZANO', 'WOW'] %} {% set custom_order = ['BTC', 'ETH', 'XMR', 'PART', 'LTC', 'BCH', 'FIRO', 'PIVX', 'DASH', 'DOGE', 'DCR', 'NMC', 'ZANO', 'WOW'] %}
{% if enabled_chart_coins is string %} {% if enabled_chart_coins is string %}
{% if enabled_chart_coins == "" %} {% if enabled_chart_coins == "" %}

View File

@@ -34,6 +34,11 @@ from tests.basicswap.common import (
PIVX_BASE_PORT, PIVX_BASE_PORT,
BTC_USE_DESCRIPTORS, BTC_USE_DESCRIPTORS,
) )
from tests.basicswap.extended.test_nmc import (
NMC_BASE_PORT,
NMC_BASE_RPC_PORT,
NMC_BASE_TOR_PORT,
)
from tests.basicswap.extended.test_dcr import ( from tests.basicswap.extended.test_dcr import (
DCR_BASE_PORT, DCR_BASE_PORT,
DCR_BASE_RPC_PORT, DCR_BASE_RPC_PORT,
@@ -50,13 +55,6 @@ from tests.basicswap.extended.test_doge import (
import basicswap.config as cfg import basicswap.config as cfg
import basicswap.bin.run as runSystem import basicswap.bin.run as runSystem
XMR_BASE_P2P_PORT = 17792
XMR_BASE_RPC_PORT = 29798
XMR_BASE_WALLET_RPC_PORT = 29998
FIRO_BASE_PORT = 34832
FIRO_BASE_RPC_PORT = 35832
FIRO_RPC_PORT_BASE = int(os.getenv("FIRO_RPC_PORT_BASE", FIRO_BASE_RPC_PORT))
TEST_PATH = os.path.expanduser(os.getenv("TEST_PATH", "~/test_basicswap1")) TEST_PATH = os.path.expanduser(os.getenv("TEST_PATH", "~/test_basicswap1"))
@@ -68,7 +66,21 @@ BITCOIN_RPC_PORT_BASE = int(os.getenv("BITCOIN_RPC_PORT_BASE", BTC_BASE_RPC_PORT
BITCOIN_TOR_PORT_BASE = int(os.getenv("BITCOIN_TOR_PORT_BASE", BTC_BASE_TOR_PORT)) BITCOIN_TOR_PORT_BASE = int(os.getenv("BITCOIN_TOR_PORT_BASE", BTC_BASE_TOR_PORT))
LITECOIN_RPC_PORT_BASE = int(os.getenv("LITECOIN_RPC_PORT_BASE", LTC_BASE_RPC_PORT)) LITECOIN_RPC_PORT_BASE = int(os.getenv("LITECOIN_RPC_PORT_BASE", LTC_BASE_RPC_PORT))
DECRED_RPC_PORT_BASE = int(os.getenv("DECRED_RPC_PORT_BASE", DCR_BASE_RPC_PORT)) DECRED_RPC_PORT_BASE = int(os.getenv("DECRED_RPC_PORT_BASE", DCR_BASE_RPC_PORT))
NAMECOIN_PORT_BASE = int(os.getenv("NAMECOIN_PORT_BASE", NMC_BASE_PORT))
NAMECOIN_RPC_PORT_BASE = int(os.getenv("NAMECOIN_RPC_PORT_BASE", NMC_BASE_RPC_PORT))
NAMECOIN_TOR_PORT_BASE = int(os.getenv("NAMECOIN_TOR_PORT_BASE", NMC_BASE_TOR_PORT))
XMR_BASE_P2P_PORT = 17792
XMR_BASE_RPC_PORT = 29798
XMR_BASE_WALLET_RPC_PORT = 29998
FIRO_BASE_PORT = 34832
FIRO_BASE_RPC_PORT = 35832
FIRO_RPC_PORT_BASE = int(os.getenv("FIRO_RPC_PORT_BASE", FIRO_BASE_RPC_PORT))
BITCOINCASH_RPC_PORT_BASE = int( BITCOINCASH_RPC_PORT_BASE = int(
os.getenv("BITCOINCASH_RPC_PORT_BASE", BCH_BASE_RPC_PORT) os.getenv("BITCOINCASH_RPC_PORT_BASE", BCH_BASE_RPC_PORT)
) )
@@ -130,19 +142,21 @@ def run_prepare(
os.environ["BTC_RPC_PORT"] = str(BITCOIN_RPC_PORT_BASE) os.environ["BTC_RPC_PORT"] = str(BITCOIN_RPC_PORT_BASE)
os.environ["BTC_PORT"] = str(BITCOIN_PORT_BASE) os.environ["BTC_PORT"] = str(BITCOIN_PORT_BASE)
os.environ["BTC_USE_DESCRIPTORS"] = str(BTC_USE_DESCRIPTORS) os.environ["BTC_USE_DESCRIPTORS"] = str(BTC_USE_DESCRIPTORS)
os.environ["BTC_ONION_PORT"] = str(BITCOIN_TOR_PORT_BASE)
os.environ["LTC_RPC_PORT"] = str(LITECOIN_RPC_PORT_BASE) os.environ["LTC_RPC_PORT"] = str(LITECOIN_RPC_PORT_BASE)
os.environ["DCR_RPC_PORT"] = str(DECRED_RPC_PORT_BASE) os.environ["DCR_RPC_PORT"] = str(DECRED_RPC_PORT_BASE)
os.environ["DCR_RPC_PWD"] = "dcr_pwd"
os.environ["NMC_RPC_PORT"] = str(NAMECOIN_RPC_PORT_BASE)
os.environ["NMC_PORT"] = str(NMC_BASE_PORT)
os.environ["NMC_ONION_PORT"] = str(NAMECOIN_TOR_PORT_BASE)
os.environ["XMR_RPC_USER"] = "xmr_user"
os.environ["XMR_RPC_PWD"] = "xmr_pwd"
os.environ["FIRO_RPC_PORT"] = str(FIRO_RPC_PORT_BASE) os.environ["FIRO_RPC_PORT"] = str(FIRO_RPC_PORT_BASE)
os.environ["BCH_PORT"] = str(BCH_BASE_PORT) os.environ["BCH_PORT"] = str(BCH_BASE_PORT)
os.environ["BCH_RPC_PORT"] = str(BITCOINCASH_RPC_PORT_BASE) os.environ["BCH_RPC_PORT"] = str(BITCOINCASH_RPC_PORT_BASE)
os.environ["DOGE_PORT"] = str(DOGE_BASE_PORT) os.environ["DOGE_PORT"] = str(DOGE_BASE_PORT)
os.environ["DOGE_RPC_PORT"] = str(DOGECOIN_RPC_PORT_BASE) os.environ["DOGE_RPC_PORT"] = str(DOGECOIN_RPC_PORT_BASE)
os.environ["XMR_RPC_USER"] = "xmr_user"
os.environ["XMR_RPC_PWD"] = "xmr_pwd"
os.environ["DCR_RPC_PWD"] = "dcr_pwd"
import basicswap.bin.prepare as prepareSystem import basicswap.bin.prepare as prepareSystem
# Hack: Reload module to set env vars as the basicswap_prepare module is initialised if imported from elsewhere earlier # Hack: Reload module to set env vars as the basicswap_prepare module is initialised if imported from elsewhere earlier
@@ -320,6 +334,62 @@ def run_prepare(
with open(config_filename, "a") as fp: with open(config_filename, "a") as fp:
fp.write("enablevoting=1\n") fp.write("enablevoting=1\n")
if "namecoin" in coins_array:
# Pruned nodes don't provide blocks
config_filename = os.path.join(datadir_path, "namecoin", "namecoin.conf")
with open(config_filename, "r") as fp:
lines = fp.readlines()
with open(config_filename, "w") as fp:
for line in lines:
if not line.startswith("prune"):
fp.write(line)
# fp.write("bind=127.0.0.1\n") # Causes BTC v28 to try and bind to bind=127.0.0.1:8444, even with a bind...=onion present
# listenonion=0 does not stop the node from trying to bind to the tor port
# https://github.com/bitcoin/bitcoin/issues/22726
fp.write(
"bind=127.0.0.1:{}=onion\n".format(
NAMECOIN_TOR_PORT_BASE + node_id + port_ofs
)
)
fp.write("dnsseed=0\n")
fp.write("discover=0\n")
fp.write("listenonion=0\n")
fp.write("upnp=0\n")
if use_rpcauth:
salt = generate_salt(16)
rpc_user = "test_nmc_" + str(node_id)
rpc_pass = "test_nmc_pwd_" + str(node_id)
fp.write(
"rpcauth={}:{}${}\n".format(
rpc_user, salt, password_to_hmac(salt, rpc_pass)
)
)
settings["chainclients"]["namecoin"]["rpcuser"] = rpc_user
settings["chainclients"]["namecoin"]["rpcpassword"] = rpc_pass
for ip in range(num_nodes):
if ip != node_id:
fp.write(
"connect=127.0.0.1:{}\n".format(
NAMECOIN_PORT_BASE + ip + port_ofs
)
)
for opt in EXTRA_CONFIG_JSON.get("ncm{}".format(node_id), []):
fp.write(opt + "\n")
if "monero" in coins_array:
with open(os.path.join(datadir_path, "monero", "monerod.conf"), "a") as fp:
fp.write("p2p-bind-ip=127.0.0.1\n")
fp.write(
"p2p-bind-port={}\n".format(XMR_BASE_P2P_PORT + node_id + port_ofs)
)
for ip in range(num_nodes):
if ip != node_id:
fp.write(
"add-exclusive-node=127.0.0.1:{}\n".format(
XMR_BASE_P2P_PORT + ip + port_ofs
)
)
if "pivx" in coins_array: if "pivx" in coins_array:
# Pruned nodes don't provide blocks # Pruned nodes don't provide blocks
config_filename = os.path.join(datadir_path, "pivx", "pivx.conf") config_filename = os.path.join(datadir_path, "pivx", "pivx.conf")
@@ -388,20 +458,6 @@ def run_prepare(
for opt in EXTRA_CONFIG_JSON.get("firo{}".format(node_id), []): for opt in EXTRA_CONFIG_JSON.get("firo{}".format(node_id), []):
fp.write(opt + "\n") fp.write(opt + "\n")
if "monero" in coins_array:
with open(os.path.join(datadir_path, "monero", "monerod.conf"), "a") as fp:
fp.write("p2p-bind-ip=127.0.0.1\n")
fp.write(
"p2p-bind-port={}\n".format(XMR_BASE_P2P_PORT + node_id + port_ofs)
)
for ip in range(num_nodes):
if ip != node_id:
fp.write(
"add-exclusive-node=127.0.0.1:{}\n".format(
XMR_BASE_P2P_PORT + ip + port_ofs
)
)
if "bitcoincash" in coins_array: if "bitcoincash" in coins_array:
config_filename = os.path.join(datadir_path, "bitcoincash", "bitcoin.conf") config_filename = os.path.join(datadir_path, "bitcoincash", "bitcoin.conf")
with open(config_filename, "r") as fp: with open(config_filename, "r") as fp:

View File

@@ -138,7 +138,6 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets # Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id) bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex() itx_spend = bid.initiate_tx.spend_txid.hex()
node_to_ci_from = swap_clients[node_to].ci(coin_from) node_to_ci_from = swap_clients[node_to].ci(coin_from)
wtx = node_to_ci_from.rpc_wallet( wtx = node_to_ci_from.rpc_wallet(
@@ -147,7 +146,9 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
itx_spend, itx_spend,
], ],
) )
assert amt_swap - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee assert (
amt_swap - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < self.max_fee
)
node_from_ci_to = swap_clients[node_from].ci(coin_to) node_from_ci_to = swap_clients[node_from].ci(coin_to)
ptx_spend = bid.participate_tx.spend_txid.hex() ptx_spend = bid.participate_tx.spend_txid.hex()
@@ -158,7 +159,8 @@ def run_test_success_path(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
js_0 = read_json_api(1800 + node_from) js_0 = read_json_api(1800 + node_from)
@@ -235,7 +237,6 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets # Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id) bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex() itx_spend = bid.initiate_tx.spend_txid.hex()
node_from_ci_from = swap_clients[node_from].ci(coin_from) node_from_ci_from = swap_clients[node_from].ci(coin_from)
wtx = node_from_ci_from.rpc_wallet( wtx = node_from_ci_from.rpc_wallet(
@@ -244,7 +245,10 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
itx_spend, itx_spend,
], ],
) )
assert amt_swap - node_from_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee assert (
amt_swap - node_from_ci_from.make_int(wtx["details"][0]["amount"])
< self.max_fee
)
node_to_ci_to = swap_clients[node_to].ci(coin_to) node_to_ci_to = swap_clients[node_to].ci(coin_to)
bid, offer = swap_clients[node_to].getBidAndOffer(bid_id) bid, offer = swap_clients[node_to].getBidAndOffer(bid_id)
@@ -255,7 +259,10 @@ def run_test_bad_ptx(self, coin_from: Coins, coin_to: Coins):
ptx_spend, ptx_spend,
], ],
) )
assert bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee assert (
bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"])
< self.max_fee
)
bid_id_hex = bid_id.hex() bid_id_hex = bid_id.hex()
path = f"bids/{bid_id_hex}/states" path = f"bids/{bid_id_hex}/states"
@@ -338,7 +345,6 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
# Verify lock tx spends are found in the expected wallets # Verify lock tx spends are found in the expected wallets
bid, offer = swap_clients[node_from].getBidAndOffer(bid_id) bid, offer = swap_clients[node_from].getBidAndOffer(bid_id)
max_fee: int = 10000
itx_spend = bid.initiate_tx.spend_txid.hex() itx_spend = bid.initiate_tx.spend_txid.hex()
node_from_ci_from = swap_clients[node_from].ci(coin_from) node_from_ci_from = swap_clients[node_from].ci(coin_from)
wtx = node_from_ci_from.rpc_wallet( wtx = node_from_ci_from.rpc_wallet(
@@ -348,7 +354,8 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
swap_value - node_from_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee swap_value - node_from_ci_from.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
node_from_ci_to = swap_clients[node_from].ci(coin_to) node_from_ci_to = swap_clients[node_from].ci(coin_to)
@@ -360,7 +367,8 @@ def run_test_itx_refund(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) < max_fee bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
@@ -425,7 +433,6 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
bid, xmr_swap = swap_clients[id_offerer].getXmrBid(bid_id) bid, xmr_swap = swap_clients[id_offerer].getXmrBid(bid_id)
node_from_ci_to = swap_clients[0].ci(coin_to) node_from_ci_to = swap_clients[0].ci(coin_to)
max_fee: int = 10000
if node_from_ci_to.coin_type() in (Coins.XMR, Coins.WOW): if node_from_ci_to.coin_type() in (Coins.XMR, Coins.WOW):
pass pass
else: else:
@@ -437,7 +444,7 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
) )
assert ( assert (
bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"]) bid.amount_to - node_from_ci_to.make_int(wtx["details"][0]["amount"])
< max_fee < self.max_fee
) )
node_to_ci_from = swap_clients[1].ci(coin_from) node_to_ci_from = swap_clients[1].ci(coin_from)
@@ -451,7 +458,8 @@ def run_test_ads_success_path(self, coin_from: Coins, coin_to: Coins):
], ],
) )
assert ( assert (
bid.amount - node_to_ci_from.make_int(wtx["details"][0]["amount"]) < max_fee bid.amount - node_to_ci_from.make_int(wtx["details"][0]["amount"])
< self.max_fee
) )
bid_id_hex = bid_id.hex() bid_id_hex = bid_id.hex()
@@ -550,7 +558,6 @@ def run_test_ads_both_refund(
bid, xmr_swap = swap_clients[id_bidder].getXmrBid(bid_id) bid, xmr_swap = swap_clients[id_bidder].getXmrBid(bid_id)
node_from_ci_from = swap_clients[0].ci(coin_from) node_from_ci_from = swap_clients[0].ci(coin_from)
max_fee: int = 10000
if node_from_ci_from.coin_type() in (Coins.XMR, Coins.WOW): if node_from_ci_from.coin_type() in (Coins.XMR, Coins.WOW):
pass pass
else: else:
@@ -562,7 +569,7 @@ def run_test_ads_both_refund(
) )
assert ( assert (
bid.amount - node_from_ci_from.make_int(wtx["details"][0]["amount"]) bid.amount - node_from_ci_from.make_int(wtx["details"][0]["amount"])
< max_fee < self.max_fee
) )
node_to_ci_to = swap_clients[1].ci(coin_to) node_to_ci_to = swap_clients[1].ci(coin_to)
@@ -577,7 +584,7 @@ def run_test_ads_both_refund(
) )
assert ( assert (
bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"]) bid.amount_to - node_to_ci_to.make_int(wtx["details"][0]["amount"])
< max_fee < self.max_fee
) )
bid_id_hex = bid_id.hex() bid_id_hex = bid_id.hex()
@@ -720,6 +727,7 @@ class Test(BaseTest):
start_xmr_nodes = True start_xmr_nodes = True
dcr_mining_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH" dcr_mining_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH"
extra_wait_time = 0 extra_wait_time = 0
max_fee: int = 10000
hex_seeds = [ hex_seeds = [
"e8574b2a94404ee62d8acc0258cab4c0defcfab8a5dfc2f4954c1f9d7e09d72a", "e8574b2a94404ee62d8acc0258cab4c0defcfab8a5dfc2f4954c1f9d7e09d72a",

View File

@@ -11,78 +11,58 @@ basicswap]$ python tests/basicswap/extended/test_nmc.py
""" """
import json
import logging import logging
import os import os
import shutil import random
import signal
import sys import sys
import threading
import time
import unittest import unittest
import basicswap.config as cfg import basicswap.config as cfg
from basicswap.basicswap import ( from basicswap.basicswap import (
BasicSwap,
Coins, Coins,
SwapTypes,
BidStates,
TxStates,
) )
from basicswap.util import ( from basicswap.util import (
COIN, toBool,
)
from basicswap.basicswap_util import (
TxLockTypes,
)
from basicswap.util.address import (
toWIF,
)
from basicswap.rpc import (
callrpc_cli,
)
from basicswap.contrib.key import (
ECKey,
)
from basicswap.http_server import (
HttpThread,
)
from tests.basicswap.util import (
read_json_api,
)
from tests.basicswap.common import (
checkForks,
stopDaemons,
wait_for_offer,
wait_for_bid,
wait_for_bid_tx_state,
wait_for_in_progress,
TEST_HTTP_HOST,
TEST_HTTP_PORT,
BASE_PORT,
BASE_RPC_PORT,
BASE_ZMQ_PORT,
PREFIX_SECRET_KEY_REGTEST,
waitForRPC,
) )
from basicswap.bin.run import startDaemon from basicswap.bin.run import startDaemon
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
from tests.basicswap.common import (
stopDaemons,
waitForRPC,
make_rpc_func,
)
from tests.basicswap.test_btc_xmr import BasicSwapTest, test_delay_event
from tests.basicswap.test_xmr import NUM_NODES
from tests.basicswap.extended.test_dcr import (
run_test_success_path,
run_test_bad_ptx,
run_test_itx_refund,
)
logger = logging.getLogger() logger = logging.getLogger("BSX Tests")
logger.level = logging.DEBUG
if not len(logger.handlers): if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))
NUM_NODES = 3
NMC_NODE = 3
BTC_NODE = 4
delay_event = threading.Event() NAMECOIN_BINDIR = os.path.expanduser(
stop_test = False os.getenv("NAMECOIN_BINDIR", os.path.join(cfg.DEFAULT_TEST_BINDIR, "namecoin"))
)
NAMECOIND = os.getenv("NAMECOIND", "namecoind" + cfg.bin_suffix)
NAMECOIN_CLI = os.getenv("NAMECOIN_CLI", "namecoin-cli" + cfg.bin_suffix)
NAMECOIN_TX = os.getenv("NAMECOIN_TX", "namecoin-tx" + cfg.bin_suffix)
NMC_USE_DESCRIPTORS = toBool(os.getenv("NMC_USE_DESCRIPTORS", True))
NMC_BASE_PORT = 8136
NMC_BASE_RPC_PORT = 8146
NMC_BASE_TOR_PORT = 8156
def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"): def prepareNMCDataDir(datadir, nodeId, conf_file="namecoin.conf"):
node_dir = os.path.join(datadir, str(nodeId)) node_dir = os.path.join(datadir, "nmc_" + str(nodeId))
if not os.path.exists(node_dir): if not os.path.exists(node_dir):
os.makedirs(node_dir) os.makedirs(node_dir)
filePath = os.path.join(node_dir, conf_file) filePath = os.path.join(node_dir, conf_file)
@@ -90,8 +70,17 @@ def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
with open(filePath, "w+") as fp: with open(filePath, "w+") as fp:
fp.write("regtest=1\n") fp.write("regtest=1\n")
fp.write("[regtest]\n") fp.write("[regtest]\n")
fp.write("port=" + str(BASE_PORT + nodeId) + "\n")
fp.write("rpcport=" + str(BASE_RPC_PORT + nodeId) + "\n") fp.write("port=" + str(NMC_BASE_PORT + nodeId) + "\n")
fp.write("rpcport=" + str(NMC_BASE_RPC_PORT + nodeId) + "\n")
salt = generate_salt(16)
fp.write(
"rpcauth={}:{}${}\n".format(
"test" + str(nodeId),
salt,
password_to_hmac(salt, "test_pass" + str(nodeId)),
)
)
fp.write("daemon=0\n") fp.write("daemon=0\n")
fp.write("printtoconsole=0\n") fp.write("printtoconsole=0\n")
@@ -99,595 +88,182 @@ def prepareOtherDir(datadir, nodeId, conf_file="namecoin.conf"):
fp.write("discover=0\n") fp.write("discover=0\n")
fp.write("listenonion=0\n") fp.write("listenonion=0\n")
fp.write("bind=127.0.0.1\n") fp.write("bind=127.0.0.1\n")
fp.write("findpeers=0\n")
fp.write("debug=1\n") fp.write("debug=1\n")
fp.write("debugexclude=libevent\n") fp.write("debugexclude=libevent\n")
fp.write("fallbackfee=0.01\n") fp.write("fallbackfee=0.01\n")
fp.write("acceptnonstdtxn=0\n") fp.write("acceptnonstdtxn=0\n")
fp.write("deprecatedrpc=create_bdb\n")
if conf_file == "bitcoin.conf": fp.write("addresstype=bech32\n")
fp.write("wallet=wallet.dat\n") fp.write("changetype=bech32\n")
def prepareDir(datadir, nodeId, network_key, network_pubkey):
node_dir = os.path.join(datadir, str(nodeId))
if not os.path.exists(node_dir):
os.makedirs(node_dir)
filePath = os.path.join(node_dir, "particl.conf")
with open(filePath, "w+") as fp:
fp.write("regtest=1\n")
fp.write("[regtest]\n")
fp.write("port=" + str(BASE_PORT + nodeId) + "\n")
fp.write("rpcport=" + str(BASE_RPC_PORT + nodeId) + "\n")
fp.write("daemon=0\n")
fp.write("printtoconsole=0\n")
fp.write("server=1\n")
fp.write("discover=0\n")
fp.write("listenonion=0\n")
fp.write("bind=127.0.0.1\n")
fp.write("findpeers=0\n")
fp.write("debug=1\n")
fp.write("debugexclude=libevent\n")
fp.write("zmqpubsmsg=tcp://127.0.0.1:" + str(BASE_ZMQ_PORT + nodeId) + "\n")
fp.write("wallet=wallet.dat\n")
fp.write("fallbackfee=0.01\n")
fp.write("acceptnonstdtxn=0\n")
fp.write("minstakeinterval=5\n")
fp.write("smsgsregtestadjust=0\n")
for i in range(0, NUM_NODES): for i in range(0, NUM_NODES):
if nodeId == i: if nodeId == i:
continue continue
fp.write("addnode=127.0.0.1:%d\n" % (BASE_PORT + i)) fp.write("addnode=127.0.0.1:{}\n".format(NMC_BASE_PORT + i))
if nodeId < 2:
fp.write("spentindex=1\n")
fp.write("txindex=1\n")
basicswap_dir = os.path.join(datadir, str(nodeId), "basicswap")
if not os.path.exists(basicswap_dir):
os.makedirs(basicswap_dir)
nmcdatadir = os.path.join(datadir, str(NMC_NODE))
btcdatadir = os.path.join(datadir, str(BTC_NODE))
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
settings = {
"debug": True,
"zmqhost": "tcp://127.0.0.1",
"zmqport": BASE_ZMQ_PORT + nodeId,
"htmlhost": "127.0.0.1",
"htmlport": 12700 + nodeId,
"network_key": network_key,
"network_pubkey": network_pubkey,
"chainclients": {
"particl": {
"connection_type": "rpc",
"manage_daemon": False,
"rpcport": BASE_RPC_PORT + nodeId,
"datadir": node_dir,
"bindir": cfg.PARTICL_BINDIR,
"blocks_confirmed": 2, # Faster testing
},
"namecoin": {
"connection_type": "rpc",
"manage_daemon": False,
"rpcport": BASE_RPC_PORT + NMC_NODE,
"datadir": nmcdatadir,
"bindir": cfg.NAMECOIN_BINDIR,
"use_csv": False,
# 'use_segwit': True,
},
"bitcoin": {
"connection_type": "rpc",
"manage_daemon": False,
"rpcport": BASE_RPC_PORT + BTC_NODE,
"datadir": btcdatadir,
"bindir": cfg.BITCOIN_BINDIR,
"use_segwit": True,
},
},
"check_progress_seconds": 2,
"check_watched_seconds": 4,
"check_expired_seconds": 60,
"restrict_unknown_seed_wallets": False,
}
with open(settings_path, "w") as fp:
json.dump(settings, fp, indent=4)
def partRpc(cmd, node_id=0): class TestNMC(BasicSwapTest):
return callrpc_cli( __test__ = True
cfg.PARTICL_BINDIR, test_coin = Coins.NMC
os.path.join(cfg.TEST_DATADIRS, str(node_id)), test_coin_from = Coins.NMC
"regtest", nmc_daemons = []
cmd, start_ltc_nodes = False
cfg.PARTICL_CLI, start_xmr_nodes = True
) base_rpc_port = NMC_BASE_RPC_PORT
nmc_addr = None
max_fee: int = 200000
test_fee_rate: int = 100000 # sats/kvB
def mineBlock(self, num_blocks: int = 1) -> None:
def btcRpc(cmd): self.callnoderpc("generatetoaddress", [num_blocks, self.nmc_addr])
return callrpc_cli(
cfg.BITCOIN_BINDIR,
os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)),
"regtest",
cmd,
cfg.BITCOIN_CLI,
)
def nmcRpc(cmd):
return callrpc_cli(
cfg.NAMECOIN_BINDIR,
os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)),
"regtest",
cmd,
cfg.NAMECOIN_CLI,
)
def signal_handler(sig, frame):
global stop_test
os.write(sys.stdout.fileno(), f"Signal {sig} detected.\n".encode("utf-8"))
stop_test = True
delay_event.set()
def run_coins_loop(cls):
while not stop_test:
try:
nmcRpc("generatetoaddress 1 {}".format(cls.nmc_addr))
btcRpc("generatetoaddress 1 {}".format(cls.btc_addr))
except Exception as e:
logging.warning("run_coins_loop " + str(e))
time.sleep(1.0)
def run_loop(self):
while not stop_test:
for c in self.swap_clients:
c.update()
time.sleep(1)
def make_part_cli_rpc_func(node_id):
node_id = node_id
def rpc_func(method, params=None, wallet=None):
cmd = method
if params:
for p in params:
cmd += ' "' + p + '"'
return partRpc(cmd, node_id)
return rpc_func
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(Test, cls).setUpClass()
eckey = ECKey()
eckey.generate()
cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes())
cls.network_pubkey = eckey.get_pubkey().get_bytes().hex()
if os.path.isdir(cfg.TEST_DATADIRS):
logging.info("Removing " + cfg.TEST_DATADIRS)
shutil.rmtree(cfg.TEST_DATADIRS)
for i in range(NUM_NODES):
prepareDir(cfg.TEST_DATADIRS, i, cls.network_key, cls.network_pubkey)
prepareOtherDir(cfg.TEST_DATADIRS, NMC_NODE)
prepareOtherDir(cfg.TEST_DATADIRS, BTC_NODE, "bitcoin.conf")
cls.daemons = []
cls.swap_clients = []
cls.http_threads = []
btc_data_dir = os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE))
if os.path.exists(os.path.join(cfg.BITCOIN_BINDIR, "bitcoin-wallet")):
callrpc_cli(
cfg.BITCOIN_BINDIR,
btc_data_dir,
"regtest",
"-wallet=wallet.dat -legacy create",
"bitcoin-wallet",
)
cls.daemons.append(startDaemon(btc_data_dir, cfg.BITCOIN_BINDIR, cfg.BITCOIND))
logging.info("Started %s %d", cfg.BITCOIND, cls.daemons[-1].handle.pid)
cls.daemons.append(
startDaemon(
os.path.join(cfg.TEST_DATADIRS, str(NMC_NODE)),
cfg.NAMECOIN_BINDIR,
cfg.NAMECOIND,
)
)
logging.info("Started %s %d", cfg.NAMECOIND, cls.daemons[-1].handle.pid)
for i in range(NUM_NODES):
data_dir = os.path.join(cfg.TEST_DATADIRS, str(i))
if os.path.exists(os.path.join(cfg.PARTICL_BINDIR, "particl-wallet")):
callrpc_cli(
cfg.PARTICL_BINDIR,
data_dir,
"regtest",
"-wallet=wallet.dat -legacy create",
"particl-wallet",
)
cls.daemons.append(startDaemon(data_dir, cfg.PARTICL_BINDIR, cfg.PARTICLD))
logging.info("Started %s %d", cfg.PARTICLD, cls.daemons[-1].handle.pid)
for i in range(NUM_NODES):
rpc = make_part_cli_rpc_func(i)
waitForRPC(rpc, delay_event)
if i == 0:
rpc(
"extkeyimportmaster",
[
"abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb"
],
)
elif i == 1:
rpc(
"extkeyimportmaster",
[
"pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic",
"",
"true",
],
)
rpc("getnewextaddress", ["lblExtTest"])
rpc("rescanblockchain")
else:
rpc("extkeyimportmaster", [rpc("mnemonic", ["new"])["master"]])
rpc(
"walletsettings",
[
"stakingoptions",
json.dumps(
{"stakecombinethreshold": 100, "stakesplitthreshold": 200}
).replace('"', '\\"'),
],
)
rpc("reservebalance", ["false"])
basicswap_dir = os.path.join(
os.path.join(cfg.TEST_DATADIRS, str(i)), "basicswap"
)
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
with open(settings_path) as fs:
settings = json.load(fs)
sc = BasicSwap(
basicswap_dir, settings, "regtest", log_name="BasicSwap{}".format(i)
)
cls.swap_clients.append(sc)
sc.setDaemonPID(Coins.BTC, cls.daemons[0].handle.pid)
sc.setDaemonPID(Coins.NMC, cls.daemons[1].handle.pid)
sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].handle.pid)
sc.start()
t = HttpThread(TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, sc)
cls.http_threads.append(t)
t.start()
waitForRPC(nmcRpc, delay_event)
num_blocks = 500
logging.info("Mining %d namecoin blocks", num_blocks)
cls.nmc_addr = nmcRpc("getnewaddress mining_addr legacy")
nmcRpc("generatetoaddress {} {}".format(num_blocks, cls.nmc_addr))
ro = nmcRpc("getblockchaininfo")
try:
assert ro["bip9_softforks"]["csv"]["status"] == "active"
except Exception:
logging.info("nmc: csv is not active")
try:
assert ro["bip9_softforks"]["segwit"]["status"] == "active"
except Exception:
logging.info("nmc: segwit is not active")
waitForRPC(btcRpc, delay_event)
cls.btc_addr = btcRpc("getnewaddress mining_addr bech32")
logging.info("Mining %d Bitcoin blocks to %s", num_blocks, cls.btc_addr)
btcRpc("generatetoaddress {} {}".format(num_blocks, cls.btc_addr))
ro = btcRpc("getblockchaininfo")
checkForks(ro)
ro = nmcRpc("getwalletinfo")
print("nmcRpc", ro)
signal.signal(signal.SIGINT, signal_handler)
cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
cls.update_thread.start()
cls.coins_update_thread = threading.Thread(target=run_coins_loop, args=(cls,))
cls.coins_update_thread.start()
# Wait for height, or sequencelock is thrown off by genesis blocktime
num_blocks = 3
logging.info("Waiting for Particl chain height %d", num_blocks)
for i in range(60):
particl_blocks = cls.swap_clients[0].callrpc("getblockcount")
print("particl_blocks", particl_blocks)
if particl_blocks >= num_blocks:
break
delay_event.wait(1)
assert particl_blocks >= num_blocks
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
global stop_test logging.info("Finalising Namecoin Test")
logging.info("Finalising") stopDaemons(cls.nmc_daemons)
stop_test = True cls.nmc_daemons.clear()
cls.update_thread.join()
cls.coins_update_thread.join()
for t in cls.http_threads:
t.stop()
t.join()
for c in cls.swap_clients:
c.finalise()
stopDaemons(cls.daemons) super(TestNMC, cls).tearDownClass()
cls.http_threads.clear()
cls.swap_clients.clear()
cls.daemons.clear()
super(Test, cls).tearDownClass() @classmethod
def coins_loop(cls):
def test_02_part_nmc(self): super(TestNMC, cls).coins_loop()
logging.info("---------- Test PART to NMC") ci0 = cls.swap_clients[0].ci(cls.test_coin)
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.PART,
Coins.NMC,
100 * COIN,
0.1 * COIN,
100 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.ABS_LOCK_TIME,
)
wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id)
wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
wait_for_bid(
delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
)
wait_for_bid(
delay_event,
swap_clients[1],
bid_id,
BidStates.SWAP_COMPLETED,
sent=True,
wait_for=60,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
def test_03_nmc_part(self):
logging.info("---------- Test NMC to PART")
swap_clients = self.swap_clients
offer_id = swap_clients[1].postOffer(
Coins.NMC,
Coins.PART,
10 * COIN,
9.0 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.ABS_LOCK_TIME,
)
wait_for_offer(delay_event, swap_clients[0], offer_id)
offer = swap_clients[0].getOffer(offer_id)
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
wait_for_bid(delay_event, swap_clients[1], bid_id)
swap_clients[1].acceptBid(bid_id)
wait_for_in_progress(delay_event, swap_clients[0], bid_id, sent=True)
wait_for_bid(
delay_event,
swap_clients[0],
bid_id,
BidStates.SWAP_COMPLETED,
sent=True,
wait_for=60,
)
wait_for_bid(
delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
def test_04_nmc_btc(self):
logging.info("---------- Test NMC to BTC")
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
10 * COIN,
0.1 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.ABS_LOCK_TIME,
)
wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id)
wait_for_in_progress(delay_event, swap_clients[1], bid_id, sent=True)
wait_for_bid(
delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
)
wait_for_bid(
delay_event,
swap_clients[1],
bid_id,
BidStates.SWAP_COMPLETED,
sent=True,
wait_for=60,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
def test_05_refund(self):
# Seller submits initiate txn, buyer doesn't respond
logging.info("---------- Test refund, NMC to BTC")
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
10 * COIN,
0.1 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.ABS_LOCK_BLOCKS,
10,
)
wait_for_offer(delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[1].abandonBid(bid_id)
swap_clients[0].acceptBid(bid_id)
wait_for_bid(
delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
)
wait_for_bid(
delay_event,
swap_clients[1],
bid_id,
BidStates.BID_ABANDONED,
sent=True,
wait_for=60,
)
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
assert js_1["num_swapping"] == 0 and js_1["num_watched_outputs"] == 0
def test_06_self_bid(self):
logging.info("---------- Test same client, BTC to NMC")
swap_clients = self.swap_clients
js_0_before = read_json_api(1800)
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
10 * COIN,
10 * COIN,
10 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.ABS_LOCK_TIME,
)
wait_for_offer(delay_event, swap_clients[0], offer_id)
offer = swap_clients[0].getOffer(offer_id)
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id)
wait_for_bid_tx_state(
delay_event,
swap_clients[0],
bid_id,
TxStates.TX_REDEEMED,
TxStates.TX_REDEEMED,
wait_for=60,
)
wait_for_bid(
delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60
)
js_0 = read_json_api(1800)
assert js_0["num_swapping"] == 0 and js_0["num_watched_outputs"] == 0
assert (
js_0["num_recv_bids"] == js_0_before["num_recv_bids"] + 1
and js_0["num_sent_bids"] == js_0_before["num_sent_bids"] + 1
)
def test_07_error(self):
logging.info("---------- Test error, BTC to NMC, set fee above bid value")
swap_clients = self.swap_clients
offer_id = swap_clients[0].postOffer(
Coins.NMC,
Coins.BTC,
0.001 * COIN,
1.0 * COIN,
0.001 * COIN,
SwapTypes.SELLER_FIRST,
TxLockTypes.ABS_LOCK_TIME,
)
wait_for_offer(delay_event, swap_clients[0], offer_id)
offer = swap_clients[0].getOffer(offer_id)
bid_id = swap_clients[0].postBid(offer_id, offer.amount_from)
wait_for_bid(delay_event, swap_clients[0], bid_id)
swap_clients[0].acceptBid(bid_id)
try: try:
swap_clients[0].getChainClientSettings(Coins.BTC)["override_feerate"] = 10.0 if cls.nmc_addr is not None:
swap_clients[0].getChainClientSettings(Coins.NMC)["override_feerate"] = 10.0 ci0.rpc_wallet("generatetoaddress", [1, cls.nmc_addr])
wait_for_bid( except Exception as e:
delay_event, swap_clients[0], bid_id, BidStates.BID_ERROR, wait_for=60 logging.warning(f"coins_loop generate {e}")
)
swap_clients[0].abandonBid(bid_id)
finally:
del swap_clients[0].getChainClientSettings(Coins.BTC)["override_feerate"]
del swap_clients[0].getChainClientSettings(Coins.NMC)["override_feerate"]
def pass_99_delay(self): @classmethod
global stop_test def prepareExtraDataDir(cls, i: int) -> None:
logging.info("Delay") if not cls.restore_instance:
for i in range(60 * 5): prepareNMCDataDir(cfg.TEST_DATADIRS, i)
if stop_test:
break cls.nmc_daemons.append(
time.sleep(1) startDaemon(
print("delay", i) os.path.join(cfg.TEST_DATADIRS, "nmc_" + str(i)),
stop_test = True NAMECOIN_BINDIR,
NAMECOIND,
)
)
logging.info("Started {} {}".format(NAMECOIND, cls.nmc_daemons[-1].handle.pid))
nmc_rpc = make_rpc_func(i, base_rpc_port=NMC_BASE_RPC_PORT)
waitForRPC(
nmc_rpc,
test_delay_event,
rpc_command="getnetworkinfo",
max_tries=12,
)
waitForRPC(nmc_rpc, test_delay_event, rpc_command="getblockchaininfo")
if len(nmc_rpc("listwallets")) < 1:
nmc_rpc(
"createwallet",
["wallet.dat", False, True, "", False, NMC_USE_DESCRIPTORS],
)
if NMC_USE_DESCRIPTORS:
nmc_rpc(
"createwallet",
["bsx_watch", True, True, "", False, True],
)
@classmethod
def addPIDInfo(cls, sc, i):
sc.setDaemonPID(Coins.DCR, cls.nmc_daemons[i].handle.pid)
@classmethod
def addCoinSettings(cls, settings, datadir, node_id):
settings["chainclients"]["namecoin"] = {
"connection_type": "rpc",
"manage_daemon": False,
"rpcport": NMC_BASE_RPC_PORT + node_id,
"rpcuser": "test" + str(node_id),
"rpcpassword": "test_pass" + str(node_id),
"datadir": os.path.join(datadir, "nmc_" + str(node_id)),
"bindir": NAMECOIN_BINDIR,
"use_csv": True,
"use_segwit": True,
"blocks_confirmed": 1,
"use_descriptors": NMC_USE_DESCRIPTORS,
}
if NMC_USE_DESCRIPTORS:
settings["chainclients"]["namecoin"]["watch_wallet_name"] = "bsx_watch"
@classmethod
def prepareExtraCoins(cls):
ci0 = cls.swap_clients[0].ci(cls.test_coin)
if not cls.restore_instance:
for sc in cls.swap_clients:
ci = sc.ci(cls.test_coin)
ci.initialiseWallet(ci.getNewRandomKey())
cls.nmc_addr = ci0.rpc_wallet("getnewaddress", ["mining_addr", "bech32"])
else:
addrs = ci0.rpc_wallet(
"getaddressesbylabel",
[
"mining_addr",
],
)
cls.nmc_addr = addrs.keys()[0]
num_blocks: int = 500
if ci0.rpc("getblockcount") < num_blocks:
logging.info(f"Mining {num_blocks} Namecoin blocks to {cls.nmc_addr}")
ci0.rpc("generatetoaddress", [num_blocks, cls.nmc_addr])
logging.info("NMC blocks: {}".format(ci0.rpc("getblockcount")))
def test_007_hdwallet(self):
logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name))
test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b"
test_wif = (
self.swap_clients[0]
.ci(self.test_coin_from)
.encodeKey(bytes.fromhex(test_seed))
)
new_wallet_name = random.randbytes(10).hex()
self.callnoderpc(
"createwallet",
[new_wallet_name, False, False, "", False, NMC_USE_DESCRIPTORS],
)
self.callnoderpc("sethdseed", [True, test_wif], wallet=new_wallet_name)
addr = self.callnoderpc(
"getnewaddress", ["add test", "bech32"], wallet=new_wallet_name
)
self.callnoderpc("unloadwallet", [new_wallet_name])
assert addr == "ncrt1qps7hnjd866e9ynxadgseprkc2l56m00dxkl7pk"
def test_012_p2sh_p2wsh(self):
# Fee rate
pass
def test_02_sh_part_coin(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_success_path(self, Coins.PART, self.test_coin)
def test_03_sh_coin_part(self):
run_test_success_path(self, self.test_coin, Coins.PART)
def test_04_sh_part_coin_bad_ptx(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_bad_ptx(self, Coins.PART, self.test_coin)
def test_05_sh_coin_part_bad_ptx(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_bad_ptx(self, self.test_coin, Coins.PART)
def test_06_sh_part_coin_itx_refund(self):
run_test_itx_refund(self, Coins.PART, self.test_coin)
def test_07_sh_coin_part_itx_refund(self):
self.prepare_balance(self.test_coin, 200.0, 1801, 1800)
run_test_itx_refund(self, self.test_coin, Coins.PART)
def test_01_b_full_swap_reverse(self):
self.prepare_balance(self.test_coin, 100.0, 1801, 1800)
self.do_test_01_full_swap(Coins.XMR, self.test_coin_from)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -60,6 +60,7 @@ from tests.basicswap.common_xmr import (
prepare_nodes, prepare_nodes,
XMR_BASE_RPC_PORT, XMR_BASE_RPC_PORT,
DOGE_BASE_RPC_PORT, DOGE_BASE_RPC_PORT,
NMC_BASE_RPC_PORT,
) )
from basicswap.interface.dcr.rpc import callrpc as callrpc_dcr from basicswap.interface.dcr.rpc import callrpc as callrpc_dcr
import basicswap.bin.run as runSystem import basicswap.bin.run as runSystem
@@ -73,12 +74,13 @@ UI_PORT = 12700 + PORT_OFS
PARTICL_RPC_PORT_BASE = int(os.getenv("PARTICL_RPC_PORT_BASE", BASE_RPC_PORT)) PARTICL_RPC_PORT_BASE = int(os.getenv("PARTICL_RPC_PORT_BASE", BASE_RPC_PORT))
BITCOIN_RPC_PORT_BASE = int(os.getenv("BITCOIN_RPC_PORT_BASE", BTC_BASE_RPC_PORT)) BITCOIN_RPC_PORT_BASE = int(os.getenv("BITCOIN_RPC_PORT_BASE", BTC_BASE_RPC_PORT))
LITECOIN_RPC_PORT_BASE = int(os.getenv("LITECOIN_RPC_PORT_BASE", LTC_BASE_RPC_PORT)) LITECOIN_RPC_PORT_BASE = int(os.getenv("LITECOIN_RPC_PORT_BASE", LTC_BASE_RPC_PORT))
DOGECOIN_RPC_PORT_BASE = int(os.getenv("DOGECOIN_RPC_PORT_BASE", DOGE_BASE_RPC_PORT)) DECRED_WALLET_RPC_PORT_BASE = int(os.getenv("DECRED_WALLET_RPC_PORT_BASE", 9210))
NAMECOIN_RPC_PORT_BASE = int(os.getenv("NAMECOIN_RPC_PORT_BASE", NMC_BASE_RPC_PORT))
XMR_BASE_RPC_PORT = int(os.getenv("XMR_BASE_RPC_PORT", XMR_BASE_RPC_PORT))
BITCOINCASH_RPC_PORT_BASE = int( BITCOINCASH_RPC_PORT_BASE = int(
os.getenv("BITCOINCASH_RPC_PORT_BASE", BCH_BASE_RPC_PORT) os.getenv("BITCOINCASH_RPC_PORT_BASE", BCH_BASE_RPC_PORT)
) )
DECRED_WALLET_RPC_PORT_BASE = int(os.getenv("DECRED_WALLET_RPC_PORT_BASE", 9210)) DOGECOIN_RPC_PORT_BASE = int(os.getenv("DOGECOIN_RPC_PORT_BASE", DOGE_BASE_RPC_PORT))
XMR_BASE_RPC_PORT = int(os.getenv("XMR_BASE_RPC_PORT", XMR_BASE_RPC_PORT))
TEST_COINS_LIST = os.getenv("TEST_COINS_LIST", "bitcoin,monero") TEST_COINS_LIST = os.getenv("TEST_COINS_LIST", "bitcoin,monero")
NUM_NODES = int(os.getenv("NUM_NODES", 3)) NUM_NODES = int(os.getenv("NUM_NODES", 3))
@@ -130,6 +132,17 @@ def calldcrrpc(
return callrpc_dcr(base_rpc_port + node_id, auth, method, params) return callrpc_dcr(base_rpc_port + node_id, auth, method, params)
def callnmcrpc(
node_id,
method,
params=[],
wallet="wallet.dat",
base_rpc_port=NAMECOIN_RPC_PORT_BASE + PORT_OFS,
):
auth = "test_nmc_{0}:test_nmc_pwd_{0}".format(node_id)
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
def callbchrpc( def callbchrpc(
node_id, node_id,
method, method,
@@ -163,6 +176,8 @@ def updateThread(cls):
callbchrpc(0, "generatetoaddress", [1, cls.bch_addr]) callbchrpc(0, "generatetoaddress", [1, cls.bch_addr])
if cls.doge_addr is not None: if cls.doge_addr is not None:
calldogerpc(0, "generatetoaddress", [1, cls.doge_addr]) calldogerpc(0, "generatetoaddress", [1, cls.doge_addr])
if cls.nmc_addr is not None:
callnmcrpc(0, "generatetoaddress", [1, cls.nmc_addr])
except Exception as e: except Exception as e:
print("updateThread error", str(e)) print("updateThread error", str(e))
cls.delay_event.wait(random.randrange(cls.update_min, cls.update_max)) cls.delay_event.wait(random.randrange(cls.update_min, cls.update_max))
@@ -388,6 +403,18 @@ def start_processes(self):
0, "generatetoaddress", [num_blocks - have_blocks, self.doge_addr] 0, "generatetoaddress", [num_blocks - have_blocks, self.doge_addr]
) )
if "namecoin" in TEST_COINS_LIST:
self.nmc_addr = callnmcrpc(0, "getnewaddress", ["mining_addr", "bech32"])
num_blocks: int = 500
have_blocks: int = callnmcrpc(0, "getblockcount")
if have_blocks < num_blocks:
logging.info(
f"Mining {num_blocks - have_blocks} Namecoin blocks to {self.nmc_addr}"
)
callnmcrpc(
0, "generatetoaddress", [num_blocks - have_blocks, self.nmc_addr]
)
if RESET_TEST: if RESET_TEST:
# Lower output split threshold for more stakeable outputs # Lower output split threshold for more stakeable outputs
for i in range(NUM_NODES): for i in range(NUM_NODES):
@@ -444,6 +471,7 @@ class BaseTestWithPrepare(unittest.TestCase):
dcr_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH" dcr_addr = "SsYbXyjkKAEXXcGdFgr4u4bo4L8RkCxwQpH"
dcr_acc = None dcr_acc = None
doge_addr = None doge_addr = None
nmc_addr = None
initialised = False initialised = False

View File

@@ -26,6 +26,9 @@ from basicswap.db import (
from basicswap.util import ( from basicswap.util import (
make_int, make_int,
) )
from basicswap.util.address import (
decodeAddress,
)
from basicswap.util.extkey import ExtKeyPair from basicswap.util.extkey import ExtKeyPair
from basicswap.interface.base import Curves from basicswap.interface.base import Curves
from tests.basicswap.util import ( from tests.basicswap.util import (
@@ -59,7 +62,6 @@ from basicswap.contrib.test_framework.script import (
from .test_xmr import BaseTest, test_delay_event, callnoderpc from .test_xmr import BaseTest, test_delay_event, callnoderpc
logger = logging.getLogger() logger = logging.getLogger()
test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b" test_seed = "8e54a313e6df8918df6d758fafdbf127a115175fdd2238d0e908dd8093c9ac3b"
@@ -183,7 +185,7 @@ class TestFunctions(BaseTest):
bid0 = read_json_api(1800 + id_offerer, f"bids/{bid_id.hex()}") bid0 = read_json_api(1800 + id_offerer, f"bids/{bid_id.hex()}")
bid1 = read_json_api(1800 + id_bidder, f"bids/{bid_id.hex()}") bid1 = read_json_api(1800 + id_bidder, f"bids/{bid_id.hex()}")
tolerance = 1 tolerance = 2
assert bid0["ticker_from"] == ci_from.ticker() assert bid0["ticker_from"] == ci_from.ticker()
assert bid1["ticker_from"] == ci_from.ticker() assert bid1["ticker_from"] == ci_from.ticker()
assert bid0["ticker_to"] == ci_to.ticker() assert bid0["ticker_to"] == ci_to.ticker()
@@ -666,7 +668,7 @@ class TestFunctions(BaseTest):
balance_from_before: float = self.getBalance(jsw, coin_from) balance_from_before: float = self.getBalance(jsw, coin_from)
self.prepare_balance( self.prepare_balance(
coin_to, coin_to,
balance_from_before + 1, balance_from_before * 3,
1800 + id_bidder, 1800 + id_bidder,
1801 if coin_to in (Coins.XMR,) else 1800, 1801 if coin_to in (Coins.XMR,) else 1800,
) )
@@ -718,6 +720,7 @@ class TestFunctions(BaseTest):
assert False, "Should fail" assert False, "Should fail"
amt_swap -= ci_from.make_int(1) amt_swap -= ci_from.make_int(1)
rate_swap = ci_to.make_int(1.0, r=1)
offer_id = swap_clients[id_offerer].postOffer( offer_id = swap_clients[id_offerer].postOffer(
coin_from, coin_from,
coin_to, coin_to,
@@ -770,6 +773,8 @@ class TestFunctions(BaseTest):
class BasicSwapTest(TestFunctions): class BasicSwapTest(TestFunctions):
test_fee_rate: int = 1000 # sats/kvB
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(BasicSwapTest, cls).setUpClass() super(BasicSwapTest, cls).setUpClass()
@@ -1178,6 +1183,10 @@ class BasicSwapTest(TestFunctions):
logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name)) logging.info("---------- Test {} hdwallet".format(self.test_coin_from.name))
ci = self.swap_clients[0].ci(self.test_coin_from) ci = self.swap_clients[0].ci(self.test_coin_from)
if hasattr(ci, "_use_descriptors") and ci._use_descriptors:
logging.warning("Skipping test")
return
test_wif = ( test_wif = (
self.swap_clients[0] self.swap_clients[0]
.ci(self.test_coin_from) .ci(self.test_coin_from)
@@ -1236,12 +1245,7 @@ class BasicSwapTest(TestFunctions):
swap_client = self.swap_clients[0] swap_client = self.swap_clients[0]
ci = swap_client.ci(self.test_coin_from) ci = swap_client.ci(self.test_coin_from)
addr_1 = ci.rpc_wallet( addr_1 = ci.getNewAddress(True, "gettxout test 1")
"getnewaddress",
[
"gettxout test 1",
],
)
txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0]) txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0])
assert len(txid) == 64 assert len(txid) == 64
@@ -1266,12 +1270,7 @@ class BasicSwapTest(TestFunctions):
else: else:
assert addr_1 in txout["scriptPubKey"]["addresses"] assert addr_1 in txout["scriptPubKey"]["addresses"]
# Spend # Spend
addr_2 = ci.rpc_wallet( addr_2 = ci.getNewAddress(True, "gettxout test 2")
"getnewaddress",
[
"gettxout test 2",
],
)
tx_funded = ci.rpc( tx_funded = ci.rpc(
"createrawtransaction", "createrawtransaction",
[[{"txid": utxo["txid"], "vout": utxo["vout"]}], {addr_2: 0.99}], [[{"txid": utxo["txid"], "vout": utxo["vout"]}], {addr_2: 0.99}],
@@ -1297,12 +1296,7 @@ class BasicSwapTest(TestFunctions):
logging.info("---------- Test {} scantxoutset".format(self.test_coin_from.name)) logging.info("---------- Test {} scantxoutset".format(self.test_coin_from.name))
ci = self.swap_clients[0].ci(self.test_coin_from) ci = self.swap_clients[0].ci(self.test_coin_from)
addr_1 = ci.rpc_wallet( addr_1 = ci.getNewAddress(True, "scantxoutset test")
"getnewaddress",
[
"scantxoutset test",
],
)
txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0]) txid = ci.rpc_wallet("sendtoaddress", [addr_1, 1.0])
assert len(txid) == 64 assert len(txid) == 64
@@ -1323,10 +1317,7 @@ class BasicSwapTest(TestFunctions):
# Record unspents before createSCLockTx as the used ones will be locked # Record unspents before createSCLockTx as the used ones will be locked
unspents = ci.rpc_wallet("listunspent") unspents = ci.rpc_wallet("listunspent")
lockedunspents_before = ci.rpc_wallet("listlockunspent")
# fee_rate is in sats/kvB
fee_rate: int = 1000
a = ci.getNewRandomKey() a = ci.getNewRandomKey()
b = ci.getNewRandomKey() b = ci.getNewRandomKey()
@@ -1335,17 +1326,26 @@ class BasicSwapTest(TestFunctions):
lock_tx_script = pi.genScriptLockTxScript(ci, A, B) lock_tx_script = pi.genScriptLockTxScript(ci, A, B)
lock_tx = ci.createSCLockTx(amount, lock_tx_script) lock_tx = ci.createSCLockTx(amount, lock_tx_script)
lock_tx = ci.fundSCLockTx(lock_tx, fee_rate) lock_tx = ci.fundSCLockTx(lock_tx, self.test_fee_rate)
lock_tx = ci.signTxWithWallet(lock_tx) lock_tx = ci.signTxWithWallet(lock_tx)
# Check that inputs were locked
lockedunspents = ci.rpc_wallet("listlockunspent")
assert len(lockedunspents) > len(lockedunspents_before)
unspents_after = ci.rpc_wallet("listunspent") unspents_after = ci.rpc_wallet("listunspent")
assert len(unspents) > len(unspents_after) for utxo in unspents_after:
for locked_utxo in lockedunspents:
if (
locked_utxo["txid"] == utxo["txid"]
and locked_utxo["vout"] == utxo["vout"]
):
raise ValueError("Locked utxo in listunspent")
tx_decoded = ci.rpc("decoderawtransaction", [lock_tx.hex()]) tx_decoded = ci.rpc("decoderawtransaction", [lock_tx.hex()])
txid = tx_decoded["txid"] txid = tx_decoded["txid"]
vsize = tx_decoded["vsize"] vsize = tx_decoded["vsize"]
expect_fee_int = round(fee_rate * vsize / 1000) expect_fee_int = round(self.test_fee_rate * vsize / 1000)
out_value: int = 0 out_value: int = 0
for txo in tx_decoded["vout"]: for txo in tx_decoded["vout"]:
@@ -1372,7 +1372,7 @@ class BasicSwapTest(TestFunctions):
pkh_out = ci.decodeAddress(addr_out) pkh_out = ci.decodeAddress(addr_out)
fee_info = {} fee_info = {}
lock_spend_tx = ci.createSCLockSpendTx( lock_spend_tx = ci.createSCLockSpendTx(
lock_tx, lock_tx_script, pkh_out, fee_rate, fee_info=fee_info lock_tx, lock_tx_script, pkh_out, self.test_fee_rate, fee_info=fee_info
) )
vsize_estimated: int = fee_info["vsize"] vsize_estimated: int = fee_info["vsize"]
@@ -1400,11 +1400,11 @@ class BasicSwapTest(TestFunctions):
v = ci.getNewRandomKey() v = ci.getNewRandomKey()
s = ci.getNewRandomKey() s = ci.getNewRandomKey()
S = ci.getPubkey(s) S = ci.getPubkey(s)
lock_tx_b_txid = ci.publishBLockTx(v, S, amount, fee_rate) lock_tx_b_txid = ci.publishBLockTx(v, S, amount, self.test_fee_rate)
addr_out = ci.getNewAddress(True) addr_out = ci.getNewAddress(True)
lock_tx_b_spend_txid = ci.spendBLockTx( lock_tx_b_spend_txid = ci.spendBLockTx(
lock_tx_b_txid, addr_out, v, s, amount, fee_rate, 0 lock_tx_b_txid, addr_out, v, s, amount, self.test_fee_rate, 0
) )
lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid) lock_tx_b_spend = ci.getTransaction(lock_tx_b_spend_txid)
if lock_tx_b_spend is None: if lock_tx_b_spend is None:
@@ -1635,7 +1635,9 @@ class BasicSwapTest(TestFunctions):
wallet=new_wallet_name, wallet=new_wallet_name,
) )
addr = self.callnoderpc("getnewaddress", wallet=new_wallet_name) addr = self.callnoderpc(
"getnewaddress", ["test descriptors"], wallet=new_wallet_name
)
addr_info = self.callnoderpc( addr_info = self.callnoderpc(
"getaddressinfo", "getaddressinfo",
[ [
@@ -1645,7 +1647,8 @@ class BasicSwapTest(TestFunctions):
) )
assert addr_info["hdmasterfingerprint"] == "a55b7ea9" assert addr_info["hdmasterfingerprint"] == "a55b7ea9"
assert addr_info["hdkeypath"] == "m/0h/0h/0h" assert addr_info["hdkeypath"] == "m/0h/0h/0h"
assert addr == "bcrt1qps7hnjd866e9ynxadgseprkc2l56m00dvwargr" if self.test_coin_from == Coins.BTC:
assert addr == "bcrt1qps7hnjd866e9ynxadgseprkc2l56m00dvwargr"
addr_change = self.callnoderpc("getrawchangeaddress", wallet=new_wallet_name) addr_change = self.callnoderpc("getrawchangeaddress", wallet=new_wallet_name)
addr_info = self.callnoderpc( addr_info = self.callnoderpc(
@@ -1657,7 +1660,8 @@ class BasicSwapTest(TestFunctions):
) )
assert addr_info["hdmasterfingerprint"] == "a55b7ea9" assert addr_info["hdmasterfingerprint"] == "a55b7ea9"
assert addr_info["hdkeypath"] == "m/0h/1h/0h" assert addr_info["hdkeypath"] == "m/0h/1h/0h"
assert addr_change == "bcrt1qdl9ryxkqjltv42lhfnqgdjf9tagxsjpp2xak9a" if self.test_coin_from == Coins.BTC:
assert addr_change == "bcrt1qdl9ryxkqjltv42lhfnqgdjf9tagxsjpp2xak9a"
desc_watch = descsum_create(f"addr({addr})") desc_watch = descsum_create(f"addr({addr})")
self.callnoderpc( self.callnoderpc(
@@ -1683,7 +1687,56 @@ class BasicSwapTest(TestFunctions):
# Test that addresses can be generated beyond range in listdescriptors # Test that addresses can be generated beyond range in listdescriptors
for i in range(2000): for i in range(2000):
self.callnoderpc("getnewaddress", wallet=new_wallet_name) self.callnoderpc(
"getnewaddress",
[
f"t{i}",
],
wallet=new_wallet_name,
)
# https://github.com/bitcoin/bitcoin/issues/10542
# https://github.com/bitcoin/bitcoin/issues/26046
sign_for_address: str = self.callnoderpc(
"getnewaddress",
[
"sign address",
],
wallet=new_wallet_name,
)
priv_keys = self.callnoderpc("listdescriptors", [True], wallet=new_wallet_name)
addr_info = self.callnoderpc(
"getaddressinfo", [sign_for_address], wallet=new_wallet_name
)
hdkeypath = addr_info["hdkeypath"]
sign_for_address_key = None
for descriptor in priv_keys["descriptors"]:
if descriptor["active"] is False or descriptor["internal"] is True:
continue
desc = descriptor["desc"]
assert desc.startswith("wpkh(")
ext_key = desc[5:].split(")")[0].split("/", 1)[0]
ext_key_data = decodeAddress(ext_key)[4:]
ci_part = self.swap_clients[0].ci(Coins.PART)
ext_key_data_part = ci_part.encode_secret_extkey(ext_key_data)
rv = ci_part.rpc_wallet("extkey", ["info", ext_key_data_part, hdkeypath])
extkey_derived = rv["key_info"]["result"]
ext_key_data = decodeAddress(extkey_derived)[4:]
ek = ExtKeyPair()
ek.decode(ext_key_data)
addr = ci.encodeSegwitAddress(ci.getAddressHashFromKey(ek._key))
assert addr == sign_for_address
sign_for_address_key = ci.encodeKey(ek._key)
break
assert sign_for_address_key is not None
sign_message: str = "Would be better if dumpprivkey or signmessage worked"
sig = self.callnoderpc(
"signmessagewithprivkey",
[sign_for_address_key, sign_message],
wallet=new_wallet_name,
)
assert ci.verifyMessage(sign_for_address, sign_message, sig)
self.callnoderpc("unloadwallet", [new_wallet_name]) self.callnoderpc("unloadwallet", [new_wallet_name])
self.callnoderpc("unloadwallet", [new_watch_wallet_name]) self.callnoderpc("unloadwallet", [new_watch_wallet_name])