From 90544d677c4c876cf196be2307ada81cf978785b Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 17 Mar 2025 10:16:18 +0000 Subject: [PATCH] cmdtest.py: reimplement thornode server using WSGI framework --- test/cmdtest_d/ct_swap.py | 18 ++--- test/cmdtest_d/{ => httpd}/thornode.py | 92 +++++++++++++------------- 2 files changed, 55 insertions(+), 55 deletions(-) rename test/cmdtest_d/{ => httpd}/thornode.py (54%) diff --git a/test/cmdtest_d/ct_swap.py b/test/cmdtest_d/ct_swap.py index c4e2afe7..162ca7ac 100755 --- a/test/cmdtest_d/ct_swap.py +++ b/test/cmdtest_d/ct_swap.py @@ -17,20 +17,16 @@ from pathlib import Path from mmgen.protocol import init_proto from ..include.common import make_burn_addr, gr_uc from .common import dfl_bip39_file -from .thornode import run_thornode_server +from .httpd.thornode import ThornodeServer from .ct_autosign import CmdTestAutosign, CmdTestAutosignThreaded from .ct_regtest import CmdTestRegtest, rt_data, dfl_wcls, rt_pw, cfg, strip_ansi_escapes +thornode_server = ThornodeServer() + sample1 = gr_uc[:24] sample2 = '00010203040506' -def thornode_server_start(): - import threading - t = threading.Thread(target=run_thornode_server, name='Thornode server thread') - t.daemon = True - t.start() - class CmdTestSwap(CmdTestRegtest, CmdTestAutosignThreaded): bdb_wallet = True networks = ('btc',) @@ -48,6 +44,7 @@ class CmdTestSwap(CmdTestRegtest, CmdTestAutosignThreaded): ('subgroup.signsend', ['init_swap']), ('subgroup.signsend_bad', ['init_swap']), ('subgroup.autosign', ['init_data', 'signsend']), + ('thornode_server_stop', 'stopping the Thornode server'), ('stop', 'stopping regtest daemons'), ) cmd_subgroups = { @@ -175,7 +172,7 @@ class CmdTestSwap(CmdTestRegtest, CmdTestAutosignThreaded): self.protos = [init_proto(cfg, k, network='regtest', need_amt=True) for k in ('btc', 'ltc', 'bch')] - thornode_server_start() # TODO: stop server when test group finishes executing + thornode_server.start() self.opts.append('--bob') @@ -732,3 +729,8 @@ class CmdTestSwap(CmdTestRegtest, CmdTestAutosignThreaded): data = self._do_cli(['getrawmempool'], add_opts=[f'--coin={self.protos[proto_idx].coin}']) assert data return 'ok' + + def thornode_server_stop(self): + self.spawn(msg_only=True) + thornode_server.stop() + return 'ok' diff --git a/test/cmdtest_d/thornode.py b/test/cmdtest_d/httpd/thornode.py similarity index 54% rename from test/cmdtest_d/thornode.py rename to test/cmdtest_d/httpd/thornode.py index 49c70aba..131eaa59 100755 --- a/test/cmdtest_d/thornode.py +++ b/test/cmdtest_d/httpd/thornode.py @@ -1,21 +1,29 @@ #!/usr/bin/env python3 +# +# MMGen Wallet, a terminal-based cryptocurrency wallet +# Copyright (C)2013-2025 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen-wallet +# https://gitlab.com/mmgen/mmgen-wallet -import json, re, time -from http.server import HTTPServer, BaseHTTPRequestHandler +""" +test.cmdtest_d.httpd.thornode: Thornode WSGI http server +""" + +import time, re, json from mmgen.cfg import Config -from mmgen.util import msg, make_timestr + +from . import HTTPD cfg = Config() -def make_inbound_addr(proto, mmtype): - from mmgen.tool.coin import tool_cmd - n = int(time.time()) // (60 * 60 * 24) # increments once every 24 hrs - return tool_cmd( - cfg = cfg, - cmdname = 'pubhash2addr', - proto = proto, - mmtype = mmtype).pubhash2addr(f'{n:040x}') +# https://thornode.ninerealms.com/thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000 +sample_request = 'GET /thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000000' +request_pat = r'/thorchain/quote/swap\?from_asset=(\S+)\.(\S+)&to_asset=(\S+)\.(\S+)&amount=(\d+)' +prices = { 'BTC': 97000, 'LTC': 115, 'BCH': 330 } data_template = { 'inbound_address': None, @@ -45,45 +53,35 @@ data_template = { 'total_swap_seconds': 2430 } -# https://thornode.ninerealms.com/thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000 +def make_inbound_addr(proto, mmtype): + from mmgen.tool.coin import tool_cmd + n = int(time.time()) // (60 * 60 * 24) # increments once every 24 hrs + return tool_cmd( + cfg = cfg, + cmdname = 'pubhash2addr', + proto = proto, + mmtype = mmtype).pubhash2addr(f'{n:040x}') -sample_request = 'GET /thorchain/quote/swap?from_asset=BCH.BCH&to_asset=LTC.LTC&amount=1000000000 HTTP/1.1' +class ThornodeServer(HTTPD): + name = 'thornode server' + port = 18800 + content_type = 'application/json' -request_pat = r'/thorchain/quote/swap\?from_asset=(\S+)\.(\S+)&to_asset=(\S+)\.(\S+)&amount=(\d+) HTTP/' + def make_response_body(self, method, environ): + from wsgiref.util import request_uri -prices = { 'BTC': 97000, 'LTC': 115, 'BCH': 330 } - -def create_data(request_line): - m = re.search(request_pat, request_line) - try: + m = re.search(request_pat, request_uri(environ)) _, send_coin, _, recv_coin, amt_atomic = m.groups() - except Exception as e: - msg(f'{type(e)}: {e}') - return {} - from mmgen.protocol import init_proto - send_proto = init_proto(cfg, send_coin, network='regtest', need_amt=True) - in_amt = send_proto.coin_amt(int(amt_atomic), from_unit='satoshi') - out_amt = in_amt * (prices[send_coin] / prices[recv_coin]) + from mmgen.protocol import init_proto + send_proto = init_proto(cfg, send_coin, network='regtest', need_amt=True) + in_amt = send_proto.coin_amt(int(amt_atomic), from_unit='satoshi') + out_amt = in_amt * (prices[send_coin] / prices[recv_coin]) - addr = make_inbound_addr(send_proto, send_proto.preferred_mmtypes[0]) - expiry = int(time.time()) + (10 * 60) - return data_template | { - 'expected_amount_out': str(out_amt.to_unit('satoshi')), - 'expiry': expiry, - 'inbound_address': addr, - } - -class handler(BaseHTTPRequestHandler): - header = b'HTTP/1.1 200 OK\nContent-type: application/json\n\n' - - def do_GET(self): - # print(f'Thornode server received:\n {self.requestline}') - self.wfile.write(self.header + json.dumps(create_data(self.requestline)).encode()) - -def run_thornode_server(server_class=HTTPServer, handler_class=handler): - print('Thornode server listening on port 18800') - server_address = ('localhost', 18800) - httpd = server_class(server_address, handler_class) - httpd.serve_forever() - print('Thornode server exiting') + addr = make_inbound_addr(send_proto, send_proto.preferred_mmtypes[0]) + data = data_template | { + 'expected_amount_out': str(out_amt.to_unit('satoshi')), + 'expiry': int(time.time()) + (10 * 60), + 'inbound_address': addr, + } + return json.dumps(data).encode()