UNPKG

banani

Version:

JS/TS library for the Banano cryptocurrency in the style of bananopie

220 lines (219 loc) 8.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RPCWithBackup = exports.RPC = void 0; /** Sends RPC requests to the RPC node, also has wrappers for actions that only read the network (write actions are handled by the Wallet class) */ class RPC { /** * @param {boolean} [use_pending = false] If true, uses "pending" instead of "receivable" in RPC action names, for compatibility with older versions of the node */ constructor(rpc_url, use_pending = false) { this.DECIMALS = undefined; //for nano, change to nano decimals this.debug = false; this.rpc_url = rpc_url; this.use_pending = use_pending; } //Network information related /** The function that sends the RPC POST request */ async call(payload) { if (this.debug) console.log(JSON.stringify(payload)); const resp = await fetch(this.rpc_url, { method: "POST", headers: this.headers ?? { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!resp.ok && this.debug) console.log(await resp.text()); if (!resp.ok) throw Error(`Request to RPC node failed with status code ${resp.status}`); const resp_json = await resp.json(); if (resp_json.error) throw Error(`RPC node response: ${resp_json.error}`); return resp_json; } /** See https://docs.nano.org/commands/rpc-protocol/#block_count */ async get_block_count() { return (await this.call({ action: "block_count", })); } /** See https://docs.nano.org/commands/rpc-protocol/#block_info */ async get_block_info(block_hash) { return (await this.call({ action: "block_info", hash: block_hash, json_block: true, })); } /** See https://docs.nano.org/commands/rpc-protocol/#blocks */ async get_blocks(block_hashes) { return (await this.call({ action: "blocks", hashes: block_hashes, json_block: true, })); } /** https://docs.nano.org/commands/rpc-protocol/#blocks_info */ async get_blocks_info(block_hashes) { return (await this.call({ action: "blocks_info", hashes: block_hashes, json_block: true, })); } /** https://docs.nano.org/commands/rpc-protocol/#representatives */ async get_representatives() { return (await this.call({ action: "representatives", })); } /** https://docs.nano.org/commands/rpc-protocol/#representatives_online */ async get_representatives_online(weight) { return (await this.call({ action: "representatives_online", weight: weight ? true : undefined, //better not to include "weight" if false, rather than sending "weight": false })); } //Account information related /** https://docs.nano.org/commands/rpc-protocol/#account_history */ async get_account_history(account, count, raw, head, offset, reverse, account_filter) { return (await this.call({ action: "account_history", account, count: `${count}`, raw: raw ? true : undefined, head, offset: offset ? `${offset}` : undefined, reverse: reverse ? true : undefined, account_filter, })); } /** https://docs.nano.org/commands/rpc-protocol/#account_info */ async get_account_info(account, include_confirmed, representative, weight, pending) { return (await this.call({ action: "account_info", account, include_confirmed: include_confirmed ? true : undefined, representative: representative ? true : undefined, weight: weight ? true : undefined, pending: pending ? true : undefined, })); } /** https://docs.nano.org/commands/rpc-protocol/#account_balance */ async get_account_balance(account) { return (await this.call({ action: "account_balance", account, })); } /** https://docs.nano.org/commands/rpc-protocol/#accounts_balances */ async get_accounts_balances(accounts) { return (await this.call({ action: "accounts_balances", accounts, })); } /** https://docs.nano.org/commands/rpc-protocol/#account_representative */ async get_account_representative(account) { return (await this.call({ action: "account_representative", account, })); } /** https://docs.nano.org/commands/rpc-protocol/#accounts_representatives */ async get_accounts_representatives(account) { return (await this.call({ action: "accounts_representatives", account, })); } /** https://docs.nano.org/commands/rpc-protocol/#account_weight */ async get_account_weight(account) { return (await this.call({ action: "account_weight", account, })); } //I hate nano node rpc here. I don't want to do the conditional type thing here, so have a union /** Keep in mind "threshold" parameter is in raw. https://docs.nano.org/commands/rpc-protocol/#receivable */ async get_account_receivable(account, count, threshold, source) { return (await this.call({ action: this.use_pending ? "pending" : "receivable", account, count: count ? `${count}` : undefined, threshold, source: source ? true : undefined, })); } /** Keep in mind "threshold" parameter is in raw. https://docs.nano.org/commands/rpc-protocol/#delegators */ async get_delegators(account, threshold, count, start) { return (await this.call({ action: "delegators", account, threshold, count: count ? `${count}` : undefined, start, })); } /** https://docs.nano.org/commands/rpc-protocol/#account_weight */ async get_delegators_count(account) { return (await this.call({ action: "account_weight", account, })); } /** https://docs.nano.org/commands/rpc-protocol/#telemetry */ async get_telemetry(raw, address, port) { return (await this.call({ action: "telemetry", raw: raw ? raw : undefined, address: address ? address : undefined, port: port ? `${port}` : undefined, })); } /** https://docs.nano.org/commands/rpc-protocol/#version */ async get_version() { return (await this.call({ action: "version", })); } } exports.RPC = RPC; class RPCWithBackup extends RPC { /** * @param {number} [timeout] Request to RPC timeout, in milliseconds. If RPC request fails or timeouts, tries the next RPC */ constructor(rpc_urls, timeout, use_pending = false) { if (rpc_urls.length < 2) throw Error("Must provide at least two RPC URLs"); super(rpc_urls[0], use_pending); this.rpc_urls = rpc_urls; this.timeout = timeout; } async call(payload) { let i = 0; while (true) { try { const resp = await fetch(this.rpc_urls[i], { method: "POST", headers: this.headers ?? { "Content-Type": "application/json" }, body: JSON.stringify(payload), signal: AbortSignal.timeout(this.timeout), //for old typescript versions }); if (!resp.ok) throw Error(`Request to RPC node failed with status code ${resp.status}`); const resp_json = await resp.json(); if (resp_json.error) throw Error(`RPC node response: ${resp_json.error}`); return resp_json; } catch (e) { //increment (so try next RPC in provided list), if all RPCs exhausted (all failed), throw error //typescript says e might not inherit from Error which is technically true, but in this case it always will be if (!this.rpc_urls[++i]) throw Error(e instanceof Error ? e.toString() : "RPC call error"); } } } } exports.RPCWithBackup = RPCWithBackup;