rpc: make rpc safe for spv mode.
This commit is contained in:
parent
666a7b7999
commit
d9a3dac869
137
lib/http/rpc.js
137
lib/http/rpc.js
@ -36,6 +36,8 @@ function RPC(node) {
|
||||
this.miner = node.miner;
|
||||
this.wallet = node.wallet;
|
||||
this.walletdb = node.walletdb;
|
||||
this.logger = node.logger;
|
||||
|
||||
this.locker = new bcoin.locker(this);
|
||||
|
||||
this.feeRate = null;
|
||||
@ -775,8 +777,12 @@ RPC.prototype.getblock = function getblock(args, callback) {
|
||||
return callback(err);
|
||||
|
||||
if (!block) {
|
||||
if (self.chain.db.options.spv)
|
||||
return callback(new RPCError('Block not available (spv mode)'));
|
||||
|
||||
if (self.chain.db.prune)
|
||||
return callback(new RPCError('Block not available (pruned data)'));
|
||||
|
||||
return callback(new RPCError('Can\'t read block from disk'));
|
||||
}
|
||||
|
||||
@ -1070,6 +1076,12 @@ RPC.prototype.getdifficulty = function getdifficulty(args, callback) {
|
||||
};
|
||||
|
||||
RPC.prototype.getmempoolinfo = function getmempoolinfo(args, callback) {
|
||||
if (args.help || args.length !== 0)
|
||||
return callback(new RPCError('getmempoolinfo'));
|
||||
|
||||
if (!this.mempool)
|
||||
return callback(new RPCError('No mempool available.'));
|
||||
|
||||
callback(null, {
|
||||
size: this.mempool.totalTX,
|
||||
bytes: this.mempool.getSize(),
|
||||
@ -1085,6 +1097,9 @@ RPC.prototype.getmempoolancestors = function getmempoolancestors(args, callback)
|
||||
if (args.help || args.length < 1 || args.length > 2)
|
||||
return callback(new RPCError('getmempoolancestors txid (verbose)'));
|
||||
|
||||
if (!this.mempool)
|
||||
return callback(new RPCError('No mempool available.'));
|
||||
|
||||
hash = toHash(args[0]);
|
||||
|
||||
if (!hash)
|
||||
@ -1117,6 +1132,9 @@ RPC.prototype.getmempooldescendants = function getmempooldescendants(args, callb
|
||||
if (args.help || args.length < 1 || args.length > 2)
|
||||
return callback(new RPCError('getmempooldescendants txid (verbose)'));
|
||||
|
||||
if (!this.mempool)
|
||||
return callback(new RPCError('No mempool available.'));
|
||||
|
||||
hash = toHash(args[0]);
|
||||
|
||||
if (!hash)
|
||||
@ -1149,6 +1167,9 @@ RPC.prototype.getmempoolentry = function getmempoolentry(args, callback) {
|
||||
if (args.help || args.length !== 1)
|
||||
return callback(new RPCError('getmempoolentry txid'));
|
||||
|
||||
if (!this.mempool)
|
||||
return callback(new RPCError('No mempool available.'));
|
||||
|
||||
hash = toHash(args[0]);
|
||||
|
||||
if (!hash)
|
||||
@ -1228,6 +1249,12 @@ RPC.prototype.gettxout = function gettxout(args, callback) {
|
||||
if (args.help || args.length < 2 || args.length > 3)
|
||||
return callback(new RPCError('gettxout "txid" n ( includemempool )'));
|
||||
|
||||
if (this.chain.db.options.spv)
|
||||
return callback(new RPCError('Cannot get coins in SPV mode.'));
|
||||
|
||||
if (this.chain.db.options.prune)
|
||||
return callback(new RPCError('Cannot get coins when pruned.'));
|
||||
|
||||
hash = toHash(args[0]);
|
||||
index = toNumber(args[1]);
|
||||
mempool = true;
|
||||
@ -1272,6 +1299,12 @@ RPC.prototype.gettxoutproof = function gettxoutproof(args, callback) {
|
||||
+ ' ["txid",...] ( blockhash )'));
|
||||
}
|
||||
|
||||
if (this.chain.db.options.spv)
|
||||
return callback(new RPCError('Cannot get coins in SPV mode.'));
|
||||
|
||||
if (this.chain.db.options.prune)
|
||||
return callback(new RPCError('Cannot get coins when pruned.'));
|
||||
|
||||
txids = toArray(args[0]);
|
||||
block = args[1];
|
||||
|
||||
@ -1370,6 +1403,9 @@ RPC.prototype.gettxoutsetinfo = function gettxoutsetinfo(args, callback) {
|
||||
if (args.help || args.length !== 0)
|
||||
return callback(new RPCError('gettxoutsetinfo'));
|
||||
|
||||
if (this.chain.db.options.spv)
|
||||
return callback(new RPCError('Chain state not available in SPV mode.'));
|
||||
|
||||
callback(null, {
|
||||
height: this.chain.height,
|
||||
bestblock: this.chain.tip.rhash,
|
||||
@ -1385,6 +1421,12 @@ RPC.prototype.verifychain = function verifychain(args, callback) {
|
||||
if (args.help || args.length > 2)
|
||||
return callback(new RPCError('verifychain ( checklevel numblocks )'));
|
||||
|
||||
if (this.chain.db.options.spv)
|
||||
return callback(new RPCError('Cannot verify chain in SPV mode.'));
|
||||
|
||||
if (this.chain.db.options.prune)
|
||||
return callback(new RPCError('Cannot verify chain when pruned.'));
|
||||
|
||||
callback();
|
||||
};
|
||||
|
||||
@ -1440,7 +1482,7 @@ RPC.prototype._submitwork = function getwork(data, callback) {
|
||||
RPC.prototype._getwork = function _getwork(callback) {
|
||||
var i, data, abbr;
|
||||
|
||||
this._getAttempt(function(err, attempt) {
|
||||
this._getAttempt(true, function(err, attempt) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -1610,7 +1652,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
||||
if (!callback)
|
||||
return;
|
||||
|
||||
this._getAttempt(function(err, attempt) {
|
||||
this._getAttempt(false, function(err, attempt) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -1695,7 +1737,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
||||
flags: attempt.coinbaseFlags.toString('hex')
|
||||
},
|
||||
coinbasevalue: attempt.coinbase.outputs[0].value,
|
||||
longpollid: self.chain.tip.rhash + utils.pad32(self.mempool.totalTX),
|
||||
longpollid: self.chain.tip.rhash + utils.pad32(self._totalTX()),
|
||||
target: utils.revHex(attempt.target.toString('hex')),
|
||||
submitold: false,
|
||||
mintime: block.ts,
|
||||
@ -1736,7 +1778,6 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
||||
};
|
||||
|
||||
RPC.prototype._poll = function _poll(lpid, callback) {
|
||||
var self = this;
|
||||
var watched, lastTX;
|
||||
|
||||
if (typeof lpid !== 'string')
|
||||
@ -1753,7 +1794,7 @@ RPC.prototype._poll = function _poll(lpid, callback) {
|
||||
|
||||
watched = utils.revHex(watched);
|
||||
|
||||
if (self.chain.tip.hash !== watched)
|
||||
if (this.chain.tip.hash !== watched)
|
||||
return callback();
|
||||
|
||||
this.once('clear block', callback);
|
||||
@ -1763,6 +1804,7 @@ RPC.prototype._clearBlock = function _clearBlock() {
|
||||
this.attempt = null;
|
||||
this.start = 0;
|
||||
this.coinbase = {};
|
||||
this.emit('clear block');
|
||||
};
|
||||
|
||||
RPC.prototype._bindChain = function _bindChain() {
|
||||
@ -1778,33 +1820,31 @@ RPC.prototype._bindChain = function _bindChain() {
|
||||
return;
|
||||
|
||||
self._clearBlock();
|
||||
self.emit('clear block');
|
||||
});
|
||||
|
||||
this.mempool.on('tx', function() {
|
||||
var diff;
|
||||
if (!this.mempool)
|
||||
return;
|
||||
|
||||
this.mempool.on('tx', function() {
|
||||
if (!self.attempt)
|
||||
return;
|
||||
|
||||
diff = utils.now() - self.start;
|
||||
|
||||
if (diff > 5) {
|
||||
if (utils.now() - self.start > 5)
|
||||
self._clearBlock();
|
||||
self.emit('clear block');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
RPC.prototype._getAttempt = function _getAttempt(callback) {
|
||||
RPC.prototype._getAttempt = function _getAttempt(update, callback) {
|
||||
var self = this;
|
||||
var attempt = this.attempt;
|
||||
|
||||
this._bindChain();
|
||||
|
||||
if (attempt) {
|
||||
attempt.updateNonce();
|
||||
this.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone();
|
||||
if (update) {
|
||||
attempt.updateNonce();
|
||||
this.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone();
|
||||
}
|
||||
return callback(null, attempt);
|
||||
}
|
||||
|
||||
@ -1820,6 +1860,10 @@ RPC.prototype._getAttempt = function _getAttempt(callback) {
|
||||
});
|
||||
};
|
||||
|
||||
RPC.prototype._totalTX = function _totalTX() {
|
||||
return this.mempool ? this.mempool.totalTX : 0;
|
||||
};
|
||||
|
||||
RPC.prototype.getmininginfo = function getmininginfo(args, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -1845,7 +1889,7 @@ RPC.prototype.getmininginfo = function getmininginfo(args, callback) {
|
||||
errors: '',
|
||||
genproclimit: self.proclimit,
|
||||
networkhashps: hashps,
|
||||
pooledtx: self.mempool.totalTX,
|
||||
pooledtx: self._totalTX(),
|
||||
testnet: self.network !== bcoin.network.main,
|
||||
chain: 'main',
|
||||
generate: self.mining
|
||||
@ -1878,6 +1922,9 @@ RPC.prototype.prioritisetransaction = function prioritisetransaction(args, callb
|
||||
+ ' <txid> <priority delta> <fee delta>'));
|
||||
}
|
||||
|
||||
if (!this.mempool)
|
||||
return callback(new RPCError('No mempool available.'));
|
||||
|
||||
hash = toHash(args[0]);
|
||||
pri = args[1];
|
||||
fee = args[2];
|
||||
@ -1990,13 +2037,23 @@ RPC.prototype.setgenerate = function setgenerate(args, callback) {
|
||||
|
||||
RPC.prototype.generate = function generate(args, callback) {
|
||||
var self = this;
|
||||
var numblocks, hashes;
|
||||
var numblocks;
|
||||
|
||||
callback = this.locker.lock(generate, [args, callback]);
|
||||
|
||||
if (!callback)
|
||||
return;
|
||||
|
||||
if (args.help || args.length < 1 || args.length > 2)
|
||||
return callback(new RPCError('generate numblocks ( maxtries )'));
|
||||
|
||||
numblocks = toNumber(args[0], 1);
|
||||
hashes = [];
|
||||
|
||||
this._generate(numblocks, callback);
|
||||
};
|
||||
|
||||
RPC.prototype._generate = function _generate(numblock, callback, force) {
|
||||
var hashes = [];
|
||||
|
||||
utils.forRangeSerial(0, numblocks, function(i, next) {
|
||||
self.miner.mineBlock(function(err, block) {
|
||||
@ -2014,23 +2071,29 @@ RPC.prototype.generate = function generate(args, callback) {
|
||||
|
||||
RPC.prototype.generatetoaddress = function generatetoaddress(args, callback) {
|
||||
var self = this;
|
||||
var address;
|
||||
var numblocks, address;
|
||||
|
||||
callback = this.locker.lock(generatetoaddress, [args, callback]);
|
||||
|
||||
if (!callback)
|
||||
return;
|
||||
|
||||
if (args.help || args.length < 2 || args.length > 3) {
|
||||
return callback(new RPCError('generatetoaddress'
|
||||
+ ' numblocks address ( maxtries )'));
|
||||
}
|
||||
|
||||
numblocks = toNumber(args[0], 1);
|
||||
address = this.miner.address;
|
||||
|
||||
this.miner.address = bcoin.address.fromBase58(toString(args[1]));
|
||||
|
||||
args = args.slice();
|
||||
args.splice(1, 1);
|
||||
|
||||
this.generate(args, function(err, hashes) {
|
||||
this._generate(numblocks, function(err, hashes) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.miner.address = address;
|
||||
|
||||
callback(null, hashes);
|
||||
});
|
||||
};
|
||||
@ -2246,7 +2309,7 @@ RPC.prototype.signrawtransaction = function signrawtransaction(args, callback) {
|
||||
|
||||
merged = txs[0];
|
||||
|
||||
this.node.fillCoins(merged, function(err) {
|
||||
this._fillCoins(merged, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -2263,6 +2326,13 @@ RPC.prototype.signrawtransaction = function signrawtransaction(args, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
RPC.prototype._fillCoins = function _fillCoins(tx, callback) {
|
||||
if (this.chain.db.options.spv)
|
||||
return callback();
|
||||
|
||||
this.node.fillCoins(tx, callback);
|
||||
};
|
||||
|
||||
RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, args, callback) {
|
||||
var keys = [];
|
||||
var keyMap = {};
|
||||
@ -2472,7 +2542,10 @@ RPC.prototype._createRedeem = function _createRedeem(args, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
/* Utility functions */
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
|
||||
RPC.prototype.createmultisig = function createmultisig(args, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -2619,6 +2692,9 @@ RPC.prototype.estimatefee = function estimatefee(args, callback) {
|
||||
if (args.help || args.length !== 1)
|
||||
return callback(new RPCError('estimatefee nblocks'));
|
||||
|
||||
if (!this.fees)
|
||||
return callback(new RPCError('Fee estimation not available.'));
|
||||
|
||||
blocks = toNumber(args[0], 1);
|
||||
|
||||
if (blocks < 1)
|
||||
@ -2640,6 +2716,9 @@ RPC.prototype.estimatepriority = function estimatepriority(args, callback) {
|
||||
if (args.help || args.length !== 1)
|
||||
return callback(new RPCError('estimatepriority nblocks'));
|
||||
|
||||
if (!this.fees)
|
||||
return callback(new RPCError('Priority estimation not available.'));
|
||||
|
||||
blocks = toNumber(args[0], 1);
|
||||
|
||||
if (blocks < 1)
|
||||
@ -2656,6 +2735,9 @@ RPC.prototype.estimatesmartfee = function estimatesmartfee(args, callback) {
|
||||
if (args.help || args.length !== 1)
|
||||
return callback(new RPCError('estimatesmartfee nblocks'));
|
||||
|
||||
if (!this.fees)
|
||||
return callback(new RPCError('Fee estimation not available.'));
|
||||
|
||||
blocks = toNumber(args[0], 1);
|
||||
|
||||
if (blocks < 1)
|
||||
@ -2680,6 +2762,9 @@ RPC.prototype.estimatesmartpriority = function estimatesmartpriority(args, callb
|
||||
if (args.help || args.length !== 1)
|
||||
return callback(new RPCError('estimatesmartpriority nblocks'));
|
||||
|
||||
if (!this.fees)
|
||||
return callback(new RPCError('Priority estimation not available.'));
|
||||
|
||||
blocks = toNumber(args[0], 1);
|
||||
|
||||
if (blocks < 1)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user