From 0c3fb2daeb8f7ce480c2cd00ca7d7ba395347b27 Mon Sep 17 00:00:00 2001 From: Kithmini Gunawardhana Date: Fri, 8 Dec 2023 10:11:03 +0530 Subject: [PATCH] Updated JS library and added modifications to support dev mode. (#306) --- README.md | 2 +- installer/jshelper/index.js | 90 +++++++++++++++------------- installer/jshelper/package-lock.json | 14 ++--- installer/jshelper/package.json | 2 +- installer/setup.sh | 25 +++----- mb-xrpl/app.js | 8 ++- mb-xrpl/lib/setup.js | 44 ++++++++++++++ mb-xrpl/package-lock.json | 14 ++--- mb-xrpl/package.json | 2 +- 9 files changed, 121 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 51f47cf..adc2afe 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Run `make installer` ('installer.tar.gz' will be placed in build directory) 1. Node app which is listening to the host xrpl account. 1. `cd mb-xrpl && npm install` (You only have to do this once) -1. `node app.js new [address] [secret] [governerAddress] [domain or ip] [leaseAmount] [rippledServer]` will create new config files called `mb-xrpl.cfg` and `secret.cfg` +1. `node app.js new [address] [secretPath] [governorAddress] [domain or ip] [leaseAmount] [rippledServer] [ipv6Subnet] [ipv6Interface] [network]` will create new config files called `mb-xrpl.cfg` and `secret.cfg` 1. `node app.js betagen [governerAddress] [domain or ip] [leaseAmount]` will generate beta host account and populate the configs. 1. `node app.js register [countryCode] [cpuMicroSec] [ramKb] [swapKb] [diskKb] [totalInstanceCount] [cpuModel] [cpuCount] [cpuSpeed] [emailAddress] [description(optional)]` will register the host on Evernode. 1. `node app.js deregister` will deregister the host from Evernode. diff --git a/installer/jshelper/index.js b/installer/jshelper/index.js index 0f675e5..e49dd9b 100644 --- a/installer/jshelper/index.js +++ b/installer/jshelper/index.js @@ -304,53 +304,57 @@ const funcs = { governorAddress: governorAddress }); - const xrplApi = new evernode.XrplApi(null, { autoReconnect: false }); - await xrplApi.connect(); + try { + const xrplApi = new evernode.XrplApi(null, { autoReconnect: false }); + await xrplApi.connect(); - evernode.Defaults.set({ - xrplApi: xrplApi - }); + evernode.Defaults.set({ + xrplApi: xrplApi + }); - const hostClient = new evernode.HostClient(accountAddress, null); - const terminateConnections = async () => { - await hostClient.disconnect(); - await xrplApi.disconnect(); - } - - let attempts = 0; - let balance = 0; - while (attempts >= 0) { - try { - // In order to handle the account not found issue via catch block. - await hostClient.connect(); - - await new Promise(resolve => setTimeout(resolve, 1000)); - if (tokenType === 'NATIVE') - balance = Number((await hostClient.xrplAcc.getInfo()).Balance) / 1000000; - else - balance = Number(await hostClient.getEVRBalance()); - - if (balance < expectedBalance) { - if (++attempts <= WAIT_PERIOD) - continue; - - await terminateConnections(); - return { success: false, result: "Funds not received within timeout." }; - } - - break; - } catch (err) { - if (err.data?.error === 'actNotFound' && ++attempts <= WAIT_PERIOD) { - await new Promise(resolve => setTimeout(resolve, 1000)); - continue; - } - await terminateConnections(); - return { success: false, result: (err.data?.error === 'actNotFound') ? "Funds not received within timeout." : "Error occurred in account balance check." }; + const hostClient = new evernode.HostClient(accountAddress, null); + const terminateConnections = async () => { + await hostClient.disconnect(); + await xrplApi.disconnect(); } - } - await terminateConnections(); - return { success: true, result: `${balance}` }; + let attempts = 0; + let balance = 0; + while (attempts >= 0) { + try { + // In order to handle the account not found issue via catch block. + await hostClient.connect(); + + await new Promise(resolve => setTimeout(resolve, 1000)); + if (tokenType === 'NATIVE') + balance = Number((await hostClient.xrplAcc.getInfo()).Balance) / 1000000; + else + balance = Number(await hostClient.getEVRBalance()); + + if (balance < expectedBalance) { + if (++attempts <= WAIT_PERIOD) + continue; + + await terminateConnections(); + return { success: false, result: "Funds not received within timeout." }; + } + + break; + } catch (err) { + if (err.data?.error === 'actNotFound' && ++attempts <= WAIT_PERIOD) { + await new Promise(resolve => setTimeout(resolve, 1000)); + continue; + } + await terminateConnections(); + return { success: false, result: (err.data?.error === 'actNotFound') ? "Funds not received within timeout." : "Error occurred in account balance check." }; + } + } + + await terminateConnections(); + return { success: true, result: `${balance}` }; + } catch { + return { success: false, result: "Error occurred in websocket connection." }; + } }, 'generate-account': async (args) => { diff --git a/installer/jshelper/package-lock.json b/installer/jshelper/package-lock.json index 95e80b7..b442faa 100644 --- a/installer/jshelper/package-lock.json +++ b/installer/jshelper/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "evernode-setup-helper", "dependencies": { - "evernode-js-client": "0.6.21", + "evernode-js-client": "0.6.23", "ip6addr": "0.2.5", "ripple-keypairs": "1.3.1" } @@ -364,9 +364,9 @@ } }, "node_modules/evernode-js-client": { - "version": "0.6.21", - "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.21.tgz", - "integrity": "sha512-Q5P6caMTzx3xaUNKhnP1vJTw3wTP/d2J2xSQEMn4m1+t/t67d8+eii3/FeQapRBSZEbNRHm9EbRry9PJhb9xcg==", + "version": "0.6.23", + "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.23.tgz", + "integrity": "sha512-MXnQLkusq8UGDcf91bSmm9AVOQ3DSfSCJwWbuQpZDsXflbK5X6Ivxjj3ABQafGjAtQLn2KDKtlfzEwRzZvpkOQ==", "dependencies": { "elliptic": "6.5.4", "libsodium-wrappers": "0.7.10", @@ -1543,9 +1543,9 @@ } }, "evernode-js-client": { - "version": "0.6.21", - "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.21.tgz", - "integrity": "sha512-Q5P6caMTzx3xaUNKhnP1vJTw3wTP/d2J2xSQEMn4m1+t/t67d8+eii3/FeQapRBSZEbNRHm9EbRry9PJhb9xcg==", + "version": "0.6.23", + "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.23.tgz", + "integrity": "sha512-MXnQLkusq8UGDcf91bSmm9AVOQ3DSfSCJwWbuQpZDsXflbK5X6Ivxjj3ABQafGjAtQLn2KDKtlfzEwRzZvpkOQ==", "requires": { "elliptic": "6.5.4", "libsodium-wrappers": "0.7.10", diff --git a/installer/jshelper/package.json b/installer/jshelper/package.json index 6cd21ba..c195561 100644 --- a/installer/jshelper/package.json +++ b/installer/jshelper/package.json @@ -4,7 +4,7 @@ "build": "ncc build index.js --minify -o dist" }, "dependencies": { - "evernode-js-client": "0.6.21", + "evernode-js-client": "0.6.23", "ip6addr": "0.2.5", "ripple-keypairs": "1.3.1" } diff --git a/installer/setup.sh b/installer/setup.sh index 43da4ec..4db7ec9 100755 --- a/installer/setup.sh +++ b/installer/setup.sh @@ -69,6 +69,7 @@ export MB_XRPL_USER="sashimbxrpl" export CG_SUFFIX="-cg" export EVERNODE_AUTO_UPDATE_SERVICE="evernode-auto-update" +# TODO Change this to mainnet in release branch while using devnet in main branch. export NETWORK="${NETWORK:-devnet}" # Private docker registry (not used for now) @@ -891,29 +892,17 @@ function set_host_xrpl_account() { # Check for saved secrets due to a previous installation. if [[ -f "$secret_backup_location" || -f "$key_file_path" ]]; then + key_file_dir=$(dirname "$key_file_path") + if [ ! -d "$key_file_dir" ]; then + mkdir -p "$key_file_dir" + fi + if [ -f "$secret_backup_location" ]; then echomult "Retrived account details via a backed-up secret." && mv $secret_backup_location $key_file_path - else - echomult "Retrived account details via a previously specified secret." fi - local existing_secret=$(jq -r '.xrpl.secret' "$key_file_path" 2>/dev/null) - if [ "$existing_secret" != "null" ] && [ "$existing_secret" != "-" ]; then - account_json=$(exec_jshelper generate-account $existing_secret) - xrpl_address=$(jq -r '.address' <<< "$account_json") - xrpl_secret=$(jq -r '.secret' <<< "$account_json") + generate_and_save_keyfile "$key_file_path" - key_file_dir=$(dirname "$key_file_path") - if [ ! -d "$key_file_dir" ]; then - mkdir -p "$key_file_dir" - fi - - # Modify the permissions accordingly - chown $MB_XRPL_USER: $key_file_path && \ - chmod 600 $key_file_path || (echomult "Error occurred in secret restoring." && exit 1) - else - echomult "Error: Backup secret file format does not support." && exit 1 - fi else echomult "Generating new keypair for the host...\n" diff --git a/mb-xrpl/app.js b/mb-xrpl/app.js index cb8195c..ddb3d75 100644 --- a/mb-xrpl/app.js +++ b/mb-xrpl/app.js @@ -17,7 +17,7 @@ async function main() { const accountAddress = process.argv[3]; const accountSecretPath = process.argv[4]; const governorAddress = process.argv[5]; - // const domain = process.argv[6]; + const domain = process.argv[6]; const leaseAmount = process.argv[7]; const rippledServer = process.argv[8]; const ipv6Subnet = (process.argv[9] === '-') ? null : process.argv[9]; @@ -25,6 +25,10 @@ async function main() { const network = process.argv.length > 11 ? process.argv[11] : appenv.NETWORK; const setup = new Setup(); setup.newConfig(accountAddress, accountSecretPath, governorAddress, parseFloat(leaseAmount), rippledServer, ipv6Subnet, ipv6NetInterface, network); + + if (appenv.IS_DEV_MODE) { + await setup.prepareHostAccount(domain); + } } else if (process.argv.length === 7 && process.argv[2] === 'betagen') { const governorAddress = process.argv[3]; @@ -81,7 +85,7 @@ async function main() { console.log(`Usage: node index.js - Run message board. node index.js version - Print version. - node index.js new [address] [secret] [governorAddress] [leaseAmount] [rippledServer] [ipv6Subnet] [ipv6Interface] [network] - Create new config files. + node index.js new [address] [secretPath] [governorAddress] [domain or ip] [leaseAmount] [rippledServer] [ipv6Subnet] [ipv6Interface] [network] - Create new config files. node index.js betagen [governorAddress] [domain or ip] [leaseAmount] [rippledServer] - Generate beta host account and populate the configs. node index.js register [countryCode] [cpuMicroSec] [ramKb] [swapKb] [diskKb] [totalInstanceCount] [description] [network] - Register the host on Evernode. node index.js transfer [transfereeAddress] - Initiate a transfer. diff --git a/mb-xrpl/lib/setup.js b/mb-xrpl/lib/setup.js index b3e9b46..1e3a38a 100644 --- a/mb-xrpl/lib/setup.js +++ b/mb-xrpl/lib/setup.js @@ -79,6 +79,50 @@ class Setup { this.#saveConfig(ipv6NetInterface ? { ...baseConfig, networking: { ipv6: { subnet: ipv6Subnet, interface: ipv6NetInterface } } } : baseConfig); } + async prepareHostAccount(domain) { + + const config = this.#getConfig(); + const acc = config.xrpl; + await setEvernodeDefaults(acc.network, acc.governorAddress, acc.rippledServer); + + // Prepare host account. + { + const hostClient = new evernode.HostClient(acc.address, acc.secret); + await hostClient.connect(); + + // Update the Defaults with "xrplApi" of the client. + evernode.Defaults.set({ + xrplApi: hostClient.xrplApi + }); + + console.log(`Preparing host account:${acc.address} (domain:${domain} registry:${hostClient.config.registryAddress})`); + + // Sometimes we may get 'account not found' error from rippled when some servers in the cluster + // haven't still updated the ledger. In such cases, we retry several times before giving up. + { + let attempts = 0; + while (attempts >= 0) { + try { + await hostClient.prepareAccount(domain); + break; + } + catch (err) { + if (err.data?.error === 'actNotFound' && ++attempts <= 5) { + console.log("actNotFound - retrying...") + // Wait and retry. + await new Promise(resolve => setTimeout(resolve, 3000)); + continue; + } + throw err; + } + } + } + + await hostClient.disconnect(); + } + + } + async generateBetaHostAccount(rippledServer, governorAddress, domain, network = null) { await setEvernodeDefaults(network, governorAddress, rippledServer); diff --git a/mb-xrpl/package-lock.json b/mb-xrpl/package-lock.json index b1f2c1e..18cfcc2 100644 --- a/mb-xrpl/package-lock.json +++ b/mb-xrpl/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "mb-xrpl", "dependencies": { - "evernode-js-client": "0.6.21", + "evernode-js-client": "0.6.23", "ip6addr": "0.2.5", "sqlite3": "5.0.2" }, @@ -980,9 +980,9 @@ } }, "node_modules/evernode-js-client": { - "version": "0.6.21", - "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.21.tgz", - "integrity": "sha512-Q5P6caMTzx3xaUNKhnP1vJTw3wTP/d2J2xSQEMn4m1+t/t67d8+eii3/FeQapRBSZEbNRHm9EbRry9PJhb9xcg==", + "version": "0.6.23", + "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.23.tgz", + "integrity": "sha512-MXnQLkusq8UGDcf91bSmm9AVOQ3DSfSCJwWbuQpZDsXflbK5X6Ivxjj3ABQafGjAtQLn2KDKtlfzEwRzZvpkOQ==", "dependencies": { "elliptic": "6.5.4", "libsodium-wrappers": "0.7.10", @@ -4010,9 +4010,9 @@ "dev": true }, "evernode-js-client": { - "version": "0.6.21", - "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.21.tgz", - "integrity": "sha512-Q5P6caMTzx3xaUNKhnP1vJTw3wTP/d2J2xSQEMn4m1+t/t67d8+eii3/FeQapRBSZEbNRHm9EbRry9PJhb9xcg==", + "version": "0.6.23", + "resolved": "https://registry.npmjs.org/evernode-js-client/-/evernode-js-client-0.6.23.tgz", + "integrity": "sha512-MXnQLkusq8UGDcf91bSmm9AVOQ3DSfSCJwWbuQpZDsXflbK5X6Ivxjj3ABQafGjAtQLn2KDKtlfzEwRzZvpkOQ==", "requires": { "elliptic": "6.5.4", "libsodium-wrappers": "0.7.10", diff --git a/mb-xrpl/package.json b/mb-xrpl/package.json index 80e8938..6ace3e6 100644 --- a/mb-xrpl/package.json +++ b/mb-xrpl/package.json @@ -5,7 +5,7 @@ "build": "npm run lint && ncc build app.js --minify -o dist" }, "dependencies": { - "evernode-js-client": "0.6.21", + "evernode-js-client": "0.6.23", "sqlite3": "5.0.2", "ip6addr": "0.2.5" },