http: rpc improvements. minor fixes.

This commit is contained in:
Christopher Jeffrey 2017-10-22 15:51:30 -07:00
parent 5ed8c0f4fe
commit a87260c959
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 196 additions and 54 deletions

17
bin/cli
View File

@ -7,6 +7,13 @@ const util = require('../lib/utils/util');
const Client = require('../lib/http/client');
const Wallet = require('../lib/http/wallet');
const ports = {
main: 8332,
testnet: 18332,
regtest: 48332,
simnet: 18556
};
const ANTIREPLAY = ''
+ '6a2e426974636f696e3a204120506565722d746f2d5065657'
+ '220456c656374726f6e696320436173682053797374656d';
@ -536,7 +543,10 @@ CLI.prototype.handleWallet = async function handleWallet() {
this.wallet = new Wallet({
url: this.config.str(['url', 'uri']),
apiKey: this.config.str('api-key'),
network: this.config.str('network'),
host: this.config.str('http-host'),
port: this.config.uint('http-port')
|| ports[this.config.str('network', '')]
|| ports.main,
id: this.config.str('id', 'primary'),
token: this.config.str('token')
});
@ -695,7 +705,10 @@ CLI.prototype.handleNode = async function handleNode() {
this.client = new Client({
url: this.config.str(['url', 'uri']),
apiKey: this.config.str('api-key'),
network: this.config.str('network')
host: this.config.str('http-host'),
port: this.config.uint('http-port')
|| ports[this.config.str('network', '')]
|| ports.main
});
switch (this.argv.shift()) {

View File

@ -36,14 +36,54 @@ const pkg = require('../pkg');
const Lock = require('../utils/lock');
const RPCBase = bweb.RPC;
const RPCError = bweb.RPCError;
const errs = bweb.errors;
/*
* Constants
*/
const errs = {
// Standard JSON-RPC 2.0 errors
INVALID_REQUEST: bweb.errors.INVALID_REQUEST,
METHOD_NOT_FOUND: bweb.errors.METHOD_NOT_FOUND,
INVALID_PARAMS: bweb.errors.INVALID_PARAMS,
INTERNAL_ERROR: bweb.errors.INTERNAL_ERROR,
PARSE_ERROR: bweb.errors.PARSE_ERROR,
// General application defined errors
MISC_ERROR: -1,
FORBIDDEN_BY_SAFE_MODE: -2,
TYPE_ERROR: -3,
INVALID_ADDRESS_OR_KEY: -5,
OUT_OF_MEMORY: -7,
INVALID_PARAMETER: -8,
DATABASE_ERROR: -20,
DESERIALIZATION_ERROR: -22,
VERIFY_ERROR: -25,
VERIFY_REJECTED: -26,
VERIFY_ALREADY_IN_CHAIN: -27,
IN_WARMUP: -28,
// P2P client errors
CLIENT_NOT_CONNECTED: -9,
CLIENT_IN_INITIAL_DOWNLOAD: -10,
CLIENT_NODE_ALREADY_ADDED: -23,
CLIENT_NODE_NOT_ADDED: -24,
CLIENT_NODE_NOT_CONNECTED: -29,
CLIENT_INVALID_IP_OR_SUBNET: -30,
CLIENT_P2P_DISABLED: -31
};
const MAGIC_STRING = 'Bitcoin Signed Message:\n';
/**
* Bitcoin RPC
* @alias module:http.RPC
* @extends bweb.RPC
*/
class RPC extends RPCBase {
/**
* Bitcoin Core RPC
* @alias module:http.RPC
* @constructor
* Create RPC.
* @param {Node} node
*/
@ -76,6 +116,41 @@ class RPC extends RPCBase {
this.init();
}
getCode(err) {
switch (err.type) {
case 'RPCError':
return err.code;
case 'ValidationError':
return errors.TYPE_ERROR;
case 'EncodingError':
return errors.DESERIALIZATION_ERROR;
default:
return errors.INTERNAL_ERROR;
}
}
handleCall(cmd, query) {
if (cmd.method !== 'getwork'
&& cmd.method !== 'getblocktemplate'
&& cmd.method !== 'getbestblockhash') {
this.logger.debug('Handling RPC call: %s.', cmd.method);
if (cmd.method !== 'submitblock'
&& cmd.method !== 'getmemorypool') {
this.logger.debug(cmd.params);
}
}
if (cmd.method === 'getwork') {
if (query.longpoll)
cmd.method = 'getworklp';
}
}
handleError(err) {
this.logger.error('RPC internal error.');
this.logger.error(err);
}
init() {
this.add('stop', this.stop);
this.add('help', this.help);
@ -154,28 +229,6 @@ class RPC extends RPCBase {
this.add('getmemoryinfo', this.getMemoryInfo);
this.add('setloglevel', this.setLogLevel);
this.on('error', (err) => {
this.logger.error('RPC internal error.');
this.logger.error(err);
});
this.on('call', (cmd, query) => {
if (cmd.method !== 'getwork'
&& cmd.method !== 'getblocktemplate'
&& cmd.method !== 'getbestblockhash') {
this.logger.debug('Handling RPC call: %s.', cmd.method);
if (cmd.method !== 'submitblock'
&& cmd.method !== 'getmemorypool') {
this.logger.debug(cmd.params);
}
}
if (cmd.method === 'getwork') {
if (query.longpoll)
cmd.method = 'getworklp';
}
});
}
/*

View File

@ -95,6 +95,17 @@ class HTTPServer extends Server {
this.use(this.jsonRPC());
this.use(this.router());
this.error((err, req, res) => {
const code = err.statusCode || 500;
res.json(code, {
error: {
type: err.type,
code: err.code,
message: err.message
}
});
});
this.get('/', async (req, res) => {
const totalTX = this.mempool ? this.mempool.map.size : 0;
const size = this.mempool ? this.mempool.getSize() : 0;
@ -163,7 +174,7 @@ class HTTPServer extends Server {
const coin = await this.node.getCoin(hash, index);
if (!coin) {
res.send(404);
res.json(404);
return;
}
@ -198,7 +209,7 @@ class HTTPServer extends Server {
const meta = await this.node.getMeta(hash);
if (!meta) {
res.send(404);
res.json(404);
return;
}
@ -256,14 +267,14 @@ class HTTPServer extends Server {
const block = await this.chain.getBlock(hash);
if (!block) {
res.send(404);
res.json(404);
return;
}
const view = await this.chain.getBlockView(block);
if (!view) {
res.send(404);
res.json(404);
return;
}
@ -306,7 +317,7 @@ class HTTPServer extends Server {
const blocks = valid.u32('blocks');
if (!this.fees) {
res.send(200, { rate: this.network.feeRate });
res.json(200, { rate: this.network.feeRate });
return;
}

View File

@ -93,6 +93,17 @@ class HTTPServer extends Server {
this.use(this.jsonRPC());
this.use(this.router());
this.error((err, req, res) => {
const code = err.statusCode || 500;
res.json(code, {
error: {
type: err.type,
code: err.code,
message: err.message
}
});
});
this.hook(async (req, res) => {
const valid = Validator.fromRequest(req);
@ -112,7 +123,7 @@ class HTTPServer extends Server {
const wallet = await this.wdb.get(id);
if (!wallet) {
res.send(404);
res.json(404);
return;
}
@ -131,7 +142,7 @@ class HTTPServer extends Server {
}
if (!wallet) {
res.send(404);
res.json(404);
return;
}
@ -234,7 +245,7 @@ class HTTPServer extends Server {
const account = await req.wallet.getAccount(acct);
if (!account) {
res.send(404);
res.json(404);
return;
}
@ -490,7 +501,7 @@ class HTTPServer extends Server {
const block = await req.wallet.getBlock(height);
if (!block) {
res.send(404);
res.json(404);
return;
}
@ -538,7 +549,7 @@ class HTTPServer extends Server {
const key = await req.wallet.getKey(addr);
if (!key) {
res.send(404);
res.json(404);
return;
}
@ -557,7 +568,7 @@ class HTTPServer extends Server {
const key = await req.wallet.getPrivateKey(addr, passphrase);
if (!key) {
res.send(404);
res.json(404);
return;
}
@ -598,7 +609,7 @@ class HTTPServer extends Server {
const balance = await req.wallet.getBalance(acct);
if (!balance) {
res.send(404);
res.json(404);
return;
}
@ -675,7 +686,7 @@ class HTTPServer extends Server {
const coin = await req.wallet.getCoin(hash, index);
if (!coin) {
res.send(404);
res.json(404);
return;
}
@ -764,7 +775,7 @@ class HTTPServer extends Server {
const tx = await req.wallet.getTX(hash);
if (!tx) {
res.send(404);
res.json(404);
return;
}

View File

@ -27,14 +27,56 @@ const Lock = require('../utils/lock');
const common = require('./common');
const RPCBase = bweb.RPC;
const RPCError = bweb.RPCError;
const errs = bweb.errors;
/*
* Constants
*/
const errs = {
// Standard JSON-RPC 2.0 errors
INVALID_REQUEST: bweb.errors.INVALID_REQUEST,
METHOD_NOT_FOUND: bweb.errors.METHOD_NOT_FOUND,
INVALID_PARAMS: bweb.errors.INVALID_PARAMS,
INTERNAL_ERROR: bweb.errors.INTERNAL_ERROR,
PARSE_ERROR: bweb.errors.PARSE_ERROR,
// General application defined errors
MISC_ERROR: -1,
FORBIDDEN_BY_SAFE_MODE: -2,
TYPE_ERROR: -3,
INVALID_ADDRESS_OR_KEY: -5,
OUT_OF_MEMORY: -7,
INVALID_PARAMETER: -8,
DATABASE_ERROR: -20,
DESERIALIZATION_ERROR: -22,
VERIFY_ERROR: -25,
VERIFY_REJECTED: -26,
VERIFY_ALREADY_IN_CHAIN: -27,
IN_WARMUP: -28,
// Wallet errors
WALLET_ERROR: -4,
WALLET_INSUFFICIENT_FUNDS: -6,
WALLET_INVALID_ACCOUNT_NAME: -11,
WALLET_KEYPOOL_RAN_OUT: -12,
WALLET_UNLOCK_NEEDED: -13,
WALLET_PASSPHRASE_INCORRECT: -14,
WALLET_WRONG_ENC_STATE: -15,
WALLET_ENCRYPTION_FAILED: -16,
WALLET_ALREADY_UNLOCKED: -17
};
const MAGIC_STRING = 'Bitcoin Signed Message:\n';
/**
* Wallet RPC
* @alias module:wallet.RPC
* @extends bweb.RPC
*/
class RPC extends RPCBase {
/**
* Bitcoin Core RPC
* @alias module:wallet.RPC
* @constructor
* Create an RPC.
* @param {WalletDB} wdb
*/
@ -54,6 +96,21 @@ class RPC extends RPCBase {
this.init();
}
getCode(err) {
switch (err.type) {
case 'RPCError':
return err.code;
case 'ValidationError':
return errors.TYPE_ERROR;
case 'EncodingError':
return errors.DESERIALIZATION_ERROR;
case 'FundingError':
return errors.WALLET_INSUFFICIENT_FUNDS;
default:
return errors.INTERNAL_ERROR;
}
}
init() {
this.add('help', this.help);
this.add('stop', this.stop);
@ -175,9 +232,9 @@ class RPC extends RPCBase {
};
}
/*
* Wallet
*/
/*
* Wallet
*/
async resendWalletTransactions(args, help) {
if (help || args.length !== 0)

View File

@ -160,8 +160,7 @@ WalletDB.prototype._open = async function _open() {
this.primary = wallet;
this.rpc.wallet = wallet;
if (this.http && this.options.listen)
await this.http.open();
await this.http.open();
};
/**
@ -172,9 +171,7 @@ WalletDB.prototype._open = async function _open() {
WalletDB.prototype._close = async function _close() {
await this.disconnect();
if (this.http && this.options.listen)
await this.http.close();
await this.http.close();
for (const wallet of this.wallets.values()) {
await wallet.destroy();