267 lines
5.4 KiB
JavaScript
Executable file
267 lines
5.4 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
'use strict';
|
|
|
|
const Config = require('bcfg');
|
|
const {NodeClient} = require('../lib/client');
|
|
|
|
// NOTE: This is part of generated `hs-client`.
|
|
// Don't introduce any unnecessary dependencies to this.
|
|
// This needs to be remain as is for hs-client to be simple.
|
|
|
|
const ports = {
|
|
main: 12037,
|
|
testnet: 13037,
|
|
regtest: 14037,
|
|
simnet: 15037
|
|
};
|
|
|
|
const HELP = `
|
|
Commands:
|
|
$ block [hash/height]: View block.
|
|
$ broadcast [tx-hex]: Broadcast transaction.
|
|
$ coin [hash+index/address]: View coins.
|
|
$ header [hash/height]: View block header.
|
|
$ help: Show help message.
|
|
$ info: Get server info.
|
|
$ mempool: Get mempool snapshot.
|
|
$ reset [height/hash]: Reset chain to desired block.
|
|
$ rpc [command] [args]: Execute RPC command.
|
|
$ tx [hash/address]: View transactions.
|
|
|
|
For additional information and a complete list of commands
|
|
visit https://hsd-dev.org/api-docs/
|
|
`;
|
|
|
|
class CLI {
|
|
constructor() {
|
|
this.config = new Config('hsd', {
|
|
suffix: 'network',
|
|
fallback: 'main',
|
|
alias: {
|
|
'n': 'network',
|
|
'u': 'url',
|
|
'uri': 'url',
|
|
'k': 'apikey',
|
|
's': 'ssl',
|
|
'h': 'httphost',
|
|
'p': 'httpport'
|
|
}
|
|
});
|
|
|
|
this.config.load({
|
|
argv: true,
|
|
env: true
|
|
});
|
|
|
|
this.config.open('hsd.conf');
|
|
|
|
this.argv = this.config.argv;
|
|
this.network = this.config.str('network', 'main');
|
|
|
|
this.client = new NodeClient({
|
|
url: this.config.str('url'),
|
|
apiKey: this.config.str('api-key'),
|
|
ssl: this.config.bool('ssl'),
|
|
host: this.config.str('http-host'),
|
|
port: this.config.uint('http-port')
|
|
|| ports[this.network]
|
|
|| ports.main,
|
|
timeout: this.config.uint('timeout'),
|
|
limit: this.config.uint('limit')
|
|
});
|
|
}
|
|
|
|
log(json) {
|
|
if (typeof json === 'string')
|
|
return console.log.apply(console, arguments);
|
|
return console.log(JSON.stringify(json, null, 2));
|
|
}
|
|
|
|
async getInfo() {
|
|
const info = await this.client.getInfo();
|
|
this.log(info);
|
|
}
|
|
|
|
async getTX() {
|
|
const hash = this.config.str(0, '');
|
|
|
|
if (hash.length !== 64) {
|
|
const txs = await this.client.getTXByAddress(hash);
|
|
this.log(txs);
|
|
return;
|
|
}
|
|
|
|
const tx = await this.client.getTX(hash);
|
|
|
|
if (!tx) {
|
|
this.log('TX not found.');
|
|
return;
|
|
}
|
|
|
|
this.log(tx);
|
|
}
|
|
|
|
async getBlock() {
|
|
let hash = this.config.str(0, '');
|
|
|
|
if (hash.length !== 64)
|
|
hash = parseInt(hash, 10);
|
|
|
|
const block = await this.client.getBlock(hash);
|
|
|
|
if (!block) {
|
|
this.log('Block not found.');
|
|
return;
|
|
}
|
|
|
|
this.log(block);
|
|
}
|
|
|
|
async getBlockHeader() {
|
|
let hash = this.config.str(0, '');
|
|
|
|
if (hash.length !== 64)
|
|
hash = parseInt(hash, 10);
|
|
|
|
const header = await this.client.getBlockHeader(hash);
|
|
|
|
if (!header) {
|
|
this.log('Block header not found.');
|
|
return;
|
|
}
|
|
|
|
this.log(header);
|
|
}
|
|
|
|
async getCoin() {
|
|
const hash = this.config.str(0, '');
|
|
const index = this.config.uint(1);
|
|
|
|
if (hash.length !== 64) {
|
|
const coins = await this.client.getCoinsByAddress(hash);
|
|
this.log(coins);
|
|
return;
|
|
}
|
|
|
|
const coin = await this.client.getCoin(hash, index);
|
|
|
|
if (!coin) {
|
|
this.log('Coin not found.');
|
|
return;
|
|
}
|
|
|
|
this.log(coin);
|
|
}
|
|
|
|
async getMempool() {
|
|
const txs = await this.client.getMempool();
|
|
|
|
this.log(txs);
|
|
}
|
|
|
|
async broadcast() {
|
|
const raw = this.config.str([0, 'tx']);
|
|
const tx = await this.client.broadcast(raw);
|
|
|
|
this.log('Broadcasted:');
|
|
this.log(tx);
|
|
}
|
|
|
|
async reset() {
|
|
let hash = this.config.str(0);
|
|
|
|
if (hash.length !== 64)
|
|
hash = parseInt(hash, 10);
|
|
|
|
await this.client.reset(hash);
|
|
|
|
this.log('Chain has been reset.');
|
|
}
|
|
|
|
async rpc() {
|
|
const method = this.argv.shift();
|
|
if (!method) {
|
|
this.log('Missing RPC method');
|
|
return;
|
|
}
|
|
|
|
const params = [];
|
|
|
|
for (const arg of this.argv) {
|
|
let param;
|
|
try {
|
|
param = JSON.parse(arg);
|
|
} catch (e) {
|
|
param = arg;
|
|
}
|
|
params.push(param);
|
|
}
|
|
|
|
let result;
|
|
try {
|
|
result = await this.client.execute(method, params);
|
|
} catch (e) {
|
|
if (e.type === 'RPCError') {
|
|
this.log(e.message);
|
|
return;
|
|
}
|
|
throw e;
|
|
}
|
|
|
|
this.log(result);
|
|
}
|
|
|
|
async open() {
|
|
switch (this.argv.shift()) {
|
|
case 'block':
|
|
await this.getBlock();
|
|
break;
|
|
case 'broadcast':
|
|
await this.broadcast();
|
|
break;
|
|
case 'coin':
|
|
await this.getCoin();
|
|
break;
|
|
case 'header':
|
|
await this.getBlockHeader();
|
|
break;
|
|
case 'help':
|
|
process.stdout.write(HELP + '\n');
|
|
break;
|
|
case 'info':
|
|
await this.getInfo();
|
|
break;
|
|
case 'mempool':
|
|
await this.getMempool();
|
|
break;
|
|
case 'reset':
|
|
await this.reset();
|
|
break;
|
|
case 'rpc':
|
|
await this.rpc();
|
|
break;
|
|
case 'tx':
|
|
await this.getTX();
|
|
break;
|
|
default:
|
|
process.stdout.write('Unrecognized command.\n');
|
|
process.stdout.write(HELP + '\n');
|
|
break;
|
|
}
|
|
}
|
|
|
|
async destroy() {
|
|
if (this.client && this.client.opened)
|
|
await this.client.close();
|
|
}
|
|
}
|
|
|
|
(async () => {
|
|
const cli = new CLI();
|
|
await cli.open();
|
|
await cli.destroy();
|
|
})().catch((err) => {
|
|
console.error(err.stack);
|
|
process.exit(1);
|
|
});
|