cmdtest.py: reimplement thornode server using WSGI framework

This commit is contained in:
The MMGen Project 2025-03-17 10:16:18 +00:00
commit 90544d677c
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
2 changed files with 55 additions and 55 deletions

View file

@ -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'

View file

@ -1,21 +1,29 @@
#!/usr/bin/env python3
#
# MMGen Wallet, a terminal-based cryptocurrency wallet
# Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
# 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()