rpc: getwork longpolling and other improvements.
This commit is contained in:
parent
d1cfcca3d9
commit
666a7b7999
@ -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 = [];
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user