From e17104d3a3975c0517fc1a2c4a5a9c0d3b7a9b5f Mon Sep 17 00:00:00 2001 From: Taariq Levack Date: Tue, 12 Jul 2022 16:58:18 +0200 Subject: [PATCH 1/3] Port dev image faucet from python to node #957 --- .../docker/devimage/faucet/faucet_server.js | 155 ++++++++++++++++++ .../docker/devimage/faucet/requirements.txt | 4 - deployment/docker/devimage/faucet/svc.py | 86 ---------- deployment/dockerfiles/dev-image.Dockerfile | 12 +- 4 files changed, 156 insertions(+), 101 deletions(-) create mode 100644 deployment/docker/devimage/faucet/faucet_server.js delete mode 100644 deployment/docker/devimage/faucet/requirements.txt delete mode 100755 deployment/docker/devimage/faucet/svc.py diff --git a/deployment/docker/devimage/faucet/faucet_server.js b/deployment/docker/devimage/faucet/faucet_server.js new file mode 100644 index 000000000..3739488ce --- /dev/null +++ b/deployment/docker/devimage/faucet/faucet_server.js @@ -0,0 +1,155 @@ +const http = require("http"); +const querystring = require("querystring"); +const exec = require("child_process").exec; + +const FAUCET_WALLET_NAME = process.env.FAUCET_WALLET_NAME || "a"; +const FAUCET_AMOUNT = process.env.FAUCET_AMOUNT || "1000000000"; +const DENOM = process.env.DENOM || "uscrt"; + +let faucet_address; + +/** + * Execute a shell command and return it as a Promise. + * @param cmd {string} + * @return {Promise} + */ +function execShellCommand(cmd) { + return new Promise((resolve, reject) => { + exec(cmd, (error, stdout, stderr) => { + if (error) { + console.error("error in execShellCommand", error); + reject(error); + } else if (stderr) { + console.error("stderr in execShellCommand", stderr); + reject(stderr); + } else { + resolve(JSON.parse(stdout)); + } + }); + }); +} + +/** + * Command to send coins. + * @param src_key_name source account key name, default 'a' + * @param src_address source account's secret address + * @param dest_address destination address + * @param amount amount to send + * @returns result of executing the command. + */ +async function send_command(src_key_name, src_address, dest_address, amount) { + const send_message = `secretd tx bank send ${src_address} ${dest_address} ${amount}${DENOM} --from ${src_key_name} --gas-prices 0.25uscrt -y`; + console.log(`send_message: \n ${send_message}`); + + const result = await execShellCommand(send_message); + console.log(`Sent tokens with txhash: ${result.txhash}`); + return result.txhash; +} + +/** + * Returns the address for the requested account key. + * @param key_name faucet account key to use, default 'a' + * @returns address + */ +async function get_address(key_name) { + // Already looked up, won't change while running + if (faucet_address !== undefined) { + return faucet_address; + } + + const list_keys = "secretd keys list"; + const result = await execShellCommand(list_keys); + + for (index in result) { + const key = result[index]; + if (key["name"] == key_name) { + console.log(`Found key with address: ${key["address"]}`); + faucet_address = key["address"]; + break; + } + } + + return faucet_address; +} + +// Start the http server +const server = http.createServer(); +server.on("request", async (req, res) => { + try { + // for root or status, return the configured faucet address and amount sent + if (req.url === "/" || req.url === "/status") { + const faucet_address = await get_address(FAUCET_WALLET_NAME); + + if (faucet_address === undefined) { + console.error( + `No key account with required name: ${FAUCET_WALLET_NAME}` + ); + + res.writeHead(500, { "Content-Type": "application/json" }); + res.write( + JSON.stringify({ + error: `No key account with required name: ${FAUCET_WALLET_NAME}`, + }) + ); + res.end(); + return; + } else { + res.writeHead(200, { "Content-Type": "application/json" }); + res.write( + JSON.stringify({ + faucet_address: faucet_address, + amount: FAUCET_AMOUNT, + }) + ); + res.end(); + } + } else if (req.url.startsWith("/faucet")) { + // ensure address is present, not necessarily valid checksum + if (!req.url.startsWith("/faucet?address=")) { + res.writeHead(400, { "Content-Type": "application/json" }); + res.write(JSON.stringify({ error: "address is required" })); + res.end(); + return; + } + + const address = querystring.parse(req.url)["/faucet?address"]; + const faucet_address = await get_address(FAUCET_WALLET_NAME); + + if (faucet_address === undefined) { + console.error( + `No key account with required name: ${FAUCET_WALLET_NAME}` + ); + + res.writeHead(500, { "Content-Type": "application/json" }); + res.write( + JSON.stringify({ + error: `No key account with required name: ${FAUCET_WALLET_NAME}`, + }) + ); + res.end(); + return; + } else { + const txhash = await send_command( + FAUCET_WALLET_NAME, + faucet_address, + address, + FAUCET_AMOUNT + ); + + res.writeHead(200, { "Content-Type": "application/json" }); + res.write(JSON.stringify({ txhash: txhash })); + res.end(); + } + } else { + res.end("Invalid Request!"); + } + } catch (err) { + res.writeHead(500, { "Content-Type": "application/json" }); + res.write(JSON.stringify({ error: `${err.message}` })); + res.end(); + } +}); + +server.listen(5000); + +console.log("Secret Faucet is running on port 5000 ..."); diff --git a/deployment/docker/devimage/faucet/requirements.txt b/deployment/docker/devimage/faucet/requirements.txt deleted file mode 100644 index d25c8e802..000000000 --- a/deployment/docker/devimage/faucet/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -requests -flask -flask_cors -gunicorn \ No newline at end of file diff --git a/deployment/docker/devimage/faucet/svc.py b/deployment/docker/devimage/faucet/svc.py deleted file mode 100755 index 8ba4bd712..000000000 --- a/deployment/docker/devimage/faucet/svc.py +++ /dev/null @@ -1,86 +0,0 @@ -#! /usr/bin/python3 - -import logging -import base64 - -import subprocess -import os -import json - -from flask import Flask, request, abort, jsonify -from flask_cors import CORS -# from flask_restplus import Api, Resource -# from flask_restplus import abort - -logger = logging.getLogger(__name__) - -logging.getLogger("urllib3.connectionpool").setLevel(logging.INFO) -logging.getLogger("werkzeug").setLevel(logging.INFO) - -logger.setLevel(logging.INFO) - -application = Flask(__name__) -CORS(application) - -node_url = os.getenv("RPC_URL", 'localhost:26657') - -chain_id = os.getenv("CHAIN_ID", 'secretdev-1') - -def get_address(key_name: str) -> str: - p = subprocess.check_output(['secretd', 'keys', 'list']) - print(f'{p}') - res = '' - for key in filter(lambda x: x['name'] == key_name, json.loads(p.decode())): - res = key['address'] - if not res: - raise RuntimeError(f"No key account with required name: {key_name}") - return res - - - -def send_command(src: str, dest: str, amount: str) -> str: - exec = ['secretd', 'tx', 'bank', 'send' ] - - address = get_address(src) - - exec.append(address) - exec.append(dest) - exec.append(f'{amount}uscrt') - exec.extend(['--from', src, '--gas-prices', '0.25uscrt', '-y']) - return exec - -# @ns.param('cert', 'Base64 encoded certificate file', 'query') -@application.route('/faucet') -def get(): # pylint: disable=no-self-use - address: str = request.args.get('address') - - wallet_name = os.getenv('FAUCET_WALLET_NAME', 'a') - faucet_amount = os.getenv('FAUCET_AMOUNT', '1000000000') - - executable = send_command(wallet_name, address, faucet_amount) - - try: - logger.info(f"sending: {executable}") - resp = subprocess.check_output(executable) - res = json.loads(resp.decode()) - logger.info(f"{resp}") - if res.get("code", 0) == 0: - return jsonify(res["txhash"]) - else: - logger.error(f"Error creating transaction: {res['raw_log']}") - except Exception as e: - logger.error(f"Error while trying to create transaction: {e} - {executable}") - abort(500) - finally: - try: - os.remove(cert_file) - except Exception: - pass - - -def start_server(port): - application.run(host='0.0.0.0', port=port, debug=False) - - -if __name__ == '__main__': - start_server(8081) \ No newline at end of file diff --git a/deployment/dockerfiles/dev-image.Dockerfile b/deployment/dockerfiles/dev-image.Dockerfile index cca50315a..4d56adf64 100644 --- a/deployment/dockerfiles/dev-image.Dockerfile +++ b/deployment/dockerfiles/dev-image.Dockerfile @@ -1,17 +1,7 @@ # Final image FROM build-release -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - #### Base utilities #### - python3.8 \ - python3-pip - -COPY deployment/docker/devimage/faucet/requirements.txt . - -RUN pip install -r requirements.txt - COPY deployment/docker/devimage/bootstrap_init_no_stop.sh bootstrap_init.sh -COPY deployment/docker/devimage/faucet/svc.py . +COPY deployment/docker/devimage/faucet/faucet_server.js . ENTRYPOINT ["./bootstrap_init.sh"] \ No newline at end of file From 1d658903df9c07664074201812236c10ed204f5f Mon Sep 17 00:00:00 2001 From: Taariq Levack Date: Tue, 12 Jul 2022 17:01:24 +0200 Subject: [PATCH 2/3] Port dev image faucet from python to node #957 --- deployment/docker/devimage/bootstrap_init_no_stop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/docker/devimage/bootstrap_init_no_stop.sh b/deployment/docker/devimage/bootstrap_init_no_stop.sh index 8d15a1551..97c3c803e 100755 --- a/deployment/docker/devimage/bootstrap_init_no_stop.sh +++ b/deployment/docker/devimage/bootstrap_init_no_stop.sh @@ -65,7 +65,7 @@ perl -i -pe 's/enable-unsafe-cors = false/enable-unsafe-cors = true/' .secretd/c lcp --proxyUrl http://localhost:1316 --port 1317 --proxyPartial '' & # Setup faucet -gunicorn --bind 0.0.0.0:5000 svc & +nohup node faucet_server.js >/dev/null 2>&1 & # Setup secretcli cp $(which secretd) $(dirname $(which secretd))/secretcli From 7463e7140e0a5341cf9f134fbb1acefe88d6bc23 Mon Sep 17 00:00:00 2001 From: Taariq Levack Date: Wed, 13 Jul 2022 14:30:13 +0200 Subject: [PATCH 3/3] Port dev image faucet from python to node #961 --- deployment/docker/devimage/bootstrap_init_no_stop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/docker/devimage/bootstrap_init_no_stop.sh b/deployment/docker/devimage/bootstrap_init_no_stop.sh index 97c3c803e..677174c59 100755 --- a/deployment/docker/devimage/bootstrap_init_no_stop.sh +++ b/deployment/docker/devimage/bootstrap_init_no_stop.sh @@ -65,7 +65,7 @@ perl -i -pe 's/enable-unsafe-cors = false/enable-unsafe-cors = true/' .secretd/c lcp --proxyUrl http://localhost:1316 --port 1317 --proxyPartial '' & # Setup faucet -nohup node faucet_server.js >/dev/null 2>&1 & +setsid node faucet_server.js & # Setup secretcli cp $(which secretd) $(dirname $(which secretd))/secretcli