rpc: getwork longpolling and other improvements.

This commit is contained in:
Christopher Jeffrey 2016-09-17 18:26:54 -07:00
parent d1cfcca3d9
commit 666a7b7999
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 81 additions and 33 deletions

View File

@ -42,9 +42,10 @@ function RPC(node) {
this.mining = false;
this.proclimit = 0;
this.currentBlock = null;
this.blockStart = 0;
this.attempt = null;
this.start = 0;
this._boundChain = false;
this.coinbase = {};
}
utils.inherits(RPC, EventEmitter);
@ -102,6 +103,8 @@ RPC.prototype.execute = function execute(json, callback) {
return this.prioritisetransaction(json.params, callback);
case 'getwork':
return this.getwork(json.params, callback);
case 'getworklp':
return this.getworklp(json.params, callback);
case 'getblocktemplate':
return this.getblocktemplate(json.params, callback);
case 'submitblock':
@ -1390,20 +1393,28 @@ RPC.prototype.verifychain = function verifychain(args, callback) {
*/
RPC.prototype._submitwork = function getwork(data, callback) {
var data, block, header;
var attempt = this.attempt;
var data, block, header, cb;
if (data.length !== 128)
return callback(new RPCError('Invalid parameter.'));
if (!this.currentBlock)
return this._getwork(callback);
if (!attempt)
return callback(null, false);
data = data.slice(0, 80);
reverseEndian(data);
header = bcoin.headers.fromAbbr(data);
block = this.currentBlock.block;
cb = this.coinbase[header.merkleRoot];
if (!cb)
return callback(null, false);
block = attempt.block;
block.txs[0] = cb;
attempt.updateMerkle();
if (header.prevBlock !== block.prevBlock
|| header.merkleRoot !== block.merkleRoot
@ -1416,7 +1427,7 @@ RPC.prototype._submitwork = function getwork(data, callback) {
block.mutable = false;
block.txs[0].mutable = false;
return this.chain.add(block, function(err) {
this.chain.add(block, function(err) {
if (err) {
if (err.type === 'VerifyError')
return callback(null, false);
@ -1426,10 +1437,10 @@ RPC.prototype._submitwork = function getwork(data, callback) {
});
};
RPC.prototype._getwork = function getwork(callback) {
RPC.prototype._getwork = function _getwork(callback) {
var i, data, abbr;
this._createBlock(function(err, attempt) {
this._getAttempt(function(err, attempt) {
if (err)
return callback(err);
@ -1452,6 +1463,13 @@ RPC.prototype._getwork = function getwork(callback) {
});
};
RPC.prototype.getworklp = function getworklp(args, callback) {
var self = this;
this.once('clear block', function() {
self._getwork(callback);
});
};
RPC.prototype.getwork = function getwork(args, callback) {
var self = this;
var data;
@ -1560,12 +1578,12 @@ RPC.prototype.getblocktemplate = function getblocktemplate(args, callback) {
}
}
if (coinbasetxn && !coinbasevalue)
if (!coinbasetxn)
coinbase = false;
}
}
if (this.network !== bcoin.network.regtest) {
if (!this.network.selfConnect) {
if (this.pool.peers.all.length === 0)
return callback(new RPCError('Bitcoin is not connected!'));
@ -1592,7 +1610,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
if (!callback)
return;
this._createBlock(function(err, attempt) {
this._getAttempt(function(err, attempt) {
if (err)
return callback(err);
@ -1681,7 +1699,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
target: utils.revHex(attempt.target.toString('hex')),
submitold: false,
mintime: block.ts,
maxtime: bcoin.now(),
maxtime: bcoin.now() + 2 * 60 * 60,
mutable: mutable,
noncerange: '00000000ffffffff',
sigoplimit: attempt.witness
@ -1689,7 +1707,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
: constants.block.MAX_SIGOPS,
sizelimit: constants.block.MAX_SIZE,
weightlimit: constants.block.MAX_WEIGHT,
curtime: bcoin.now(),
curtime: block.ts,
bits: utils.hex32(block.bits),
height: attempt.height,
default_witness_commitment: attempt.witness
@ -1697,7 +1715,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
: undefined
};
if (!coinbase) {
if (coinbase) {
template.coinbaseaux = undefined;
template.coinbasevalue = undefined;
tx = block.txs[0];
@ -1742,8 +1760,9 @@ RPC.prototype._poll = function _poll(lpid, callback) {
};
RPC.prototype._clearBlock = function _clearBlock() {
this.currentBlock = null;
this.blockStart = 0;
this.attempt = null;
this.start = 0;
this.coinbase = {};
};
RPC.prototype._bindChain = function _bindChain() {
@ -1755,7 +1774,7 @@ RPC.prototype._bindChain = function _bindChain() {
this._boundChain = true;
this.chain.on('connect', function() {
if (!self.currentBlock)
if (!self.attempt)
return;
self._clearBlock();
@ -1765,10 +1784,10 @@ RPC.prototype._bindChain = function _bindChain() {
this.mempool.on('tx', function() {
var diff;
if (!self.currentBlock)
if (!self.attempt)
return;
diff = utils.now() - self.blockStart;
diff = utils.now() - self.start;
if (diff > 5) {
self._clearBlock();
@ -1777,19 +1796,26 @@ RPC.prototype._bindChain = function _bindChain() {
});
};
RPC.prototype._createBlock = function _createBlock(callback) {
RPC.prototype._getAttempt = function _getAttempt(callback) {
var self = this;
var attempt = this.attempt;
this._bindChain();
if (this.currentBlock)
return callback(null, this.currentBlock);
if (attempt) {
attempt.updateNonce();
this.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone();
return callback(null, attempt);
}
this.miner.createBlock(function(err, attempt) {
if (err)
return callback(err);
self.currentBlock = attempt;
self.blockStart = utils.now();
self.attempt = attempt;
self.start = utils.now();
self.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone();
callback(null, attempt);
});
};
@ -2208,6 +2234,9 @@ RPC.prototype.signrawtransaction = function signrawtransaction(args, callback) {
+ ' sighashtype )'));
}
if (!utils.isHex(args[0]))
return callback(new RPCError('Invalid parameter'));
raw = new Buffer(args[0], 'hex');
p = new bcoin.reader(raw);
txs = [];

View File

@ -88,6 +88,8 @@ HTTPServer.prototype._init = function _init() {
var self = this;
this.server.on('request', function(req, res) {
if (req.pathname === '/')
return;
self.logger.debug('Request for path=%s (%s).',
req.pathname, req.socket.remoteAddress);
});
@ -441,6 +443,12 @@ HTTPServer.prototype._init = function _init() {
});
}
if (req.body.method === 'getwork') {
res.setHeader('X-Long-Polling', '/?longpoll=1');
if (req.query.longpoll)
req.body.method = 'getworklp';
}
try {
self.rpc.execute(req.body, handle);
} catch (e) {

View File

@ -185,6 +185,24 @@ MinerBlock.prototype.updateCoinbase = function updateCoinbase() {
output.value = this.block.getReward(this.network);
};
/**
* Increment the extraNonce.
*/
MinerBlock.prototype.updateNonce = function updateNonce() {
this.block.ts = Math.max(bcoin.now(), this.tip.ts + 1);
// Overflow the nonce and increment the extraNonce.
this.block.nonce = 0;
this.extraNonce.iaddn(1);
// We incremented the extraNonce, need to update coinbase.
this.updateCoinbase();
// We changed the coinbase, need to update merkleRoot.
this.updateMerkle();
};
/**
* Rebuild the merkle tree and update merkle root as well as the
* timestamp (also calls {@link MinerBlock#updateCommitment}
@ -297,14 +315,7 @@ MinerBlock.prototype.findNonce = function findNonce() {
}
// Overflow the nonce and increment the extraNonce.
block.nonce = 0;
this.extraNonce.iaddn(1);
// We incremented the extraNonce, need to update coinbase.
this.updateCoinbase();
// We changed the coinbase, need to update merkleRoot.
this.updateMerkle();
this.updateNonce();
return false;
};