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.mining = false;
|
||||||
this.proclimit = 0;
|
this.proclimit = 0;
|
||||||
|
|
||||||
this.currentBlock = null;
|
this.attempt = null;
|
||||||
this.blockStart = 0;
|
this.start = 0;
|
||||||
this._boundChain = false;
|
this._boundChain = false;
|
||||||
|
this.coinbase = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.inherits(RPC, EventEmitter);
|
utils.inherits(RPC, EventEmitter);
|
||||||
@ -102,6 +103,8 @@ RPC.prototype.execute = function execute(json, callback) {
|
|||||||
return this.prioritisetransaction(json.params, callback);
|
return this.prioritisetransaction(json.params, callback);
|
||||||
case 'getwork':
|
case 'getwork':
|
||||||
return this.getwork(json.params, callback);
|
return this.getwork(json.params, callback);
|
||||||
|
case 'getworklp':
|
||||||
|
return this.getworklp(json.params, callback);
|
||||||
case 'getblocktemplate':
|
case 'getblocktemplate':
|
||||||
return this.getblocktemplate(json.params, callback);
|
return this.getblocktemplate(json.params, callback);
|
||||||
case 'submitblock':
|
case 'submitblock':
|
||||||
@ -1390,20 +1393,28 @@ RPC.prototype.verifychain = function verifychain(args, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
RPC.prototype._submitwork = function getwork(data, 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)
|
if (data.length !== 128)
|
||||||
return callback(new RPCError('Invalid parameter.'));
|
return callback(new RPCError('Invalid parameter.'));
|
||||||
|
|
||||||
if (!this.currentBlock)
|
if (!attempt)
|
||||||
return this._getwork(callback);
|
return callback(null, false);
|
||||||
|
|
||||||
data = data.slice(0, 80);
|
data = data.slice(0, 80);
|
||||||
|
|
||||||
reverseEndian(data);
|
reverseEndian(data);
|
||||||
|
|
||||||
header = bcoin.headers.fromAbbr(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
|
if (header.prevBlock !== block.prevBlock
|
||||||
|| header.merkleRoot !== block.merkleRoot
|
|| header.merkleRoot !== block.merkleRoot
|
||||||
@ -1416,7 +1427,7 @@ RPC.prototype._submitwork = function getwork(data, callback) {
|
|||||||
block.mutable = false;
|
block.mutable = false;
|
||||||
block.txs[0].mutable = false;
|
block.txs[0].mutable = false;
|
||||||
|
|
||||||
return this.chain.add(block, function(err) {
|
this.chain.add(block, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.type === 'VerifyError')
|
if (err.type === 'VerifyError')
|
||||||
return callback(null, false);
|
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;
|
var i, data, abbr;
|
||||||
|
|
||||||
this._createBlock(function(err, attempt) {
|
this._getAttempt(function(err, attempt) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(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) {
|
RPC.prototype.getwork = function getwork(args, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var data;
|
var data;
|
||||||
@ -1560,12 +1578,12 @@ RPC.prototype.getblocktemplate = function getblocktemplate(args, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coinbasetxn && !coinbasevalue)
|
if (!coinbasetxn)
|
||||||
coinbase = false;
|
coinbase = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.network !== bcoin.network.regtest) {
|
if (!this.network.selfConnect) {
|
||||||
if (this.pool.peers.all.length === 0)
|
if (this.pool.peers.all.length === 0)
|
||||||
return callback(new RPCError('Bitcoin is not connected!'));
|
return callback(new RPCError('Bitcoin is not connected!'));
|
||||||
|
|
||||||
@ -1592,7 +1610,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
|||||||
if (!callback)
|
if (!callback)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._createBlock(function(err, attempt) {
|
this._getAttempt(function(err, attempt) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
@ -1681,7 +1699,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
|||||||
target: utils.revHex(attempt.target.toString('hex')),
|
target: utils.revHex(attempt.target.toString('hex')),
|
||||||
submitold: false,
|
submitold: false,
|
||||||
mintime: block.ts,
|
mintime: block.ts,
|
||||||
maxtime: bcoin.now(),
|
maxtime: bcoin.now() + 2 * 60 * 60,
|
||||||
mutable: mutable,
|
mutable: mutable,
|
||||||
noncerange: '00000000ffffffff',
|
noncerange: '00000000ffffffff',
|
||||||
sigoplimit: attempt.witness
|
sigoplimit: attempt.witness
|
||||||
@ -1689,7 +1707,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
|||||||
: constants.block.MAX_SIGOPS,
|
: constants.block.MAX_SIGOPS,
|
||||||
sizelimit: constants.block.MAX_SIZE,
|
sizelimit: constants.block.MAX_SIZE,
|
||||||
weightlimit: constants.block.MAX_WEIGHT,
|
weightlimit: constants.block.MAX_WEIGHT,
|
||||||
curtime: bcoin.now(),
|
curtime: block.ts,
|
||||||
bits: utils.hex32(block.bits),
|
bits: utils.hex32(block.bits),
|
||||||
height: attempt.height,
|
height: attempt.height,
|
||||||
default_witness_commitment: attempt.witness
|
default_witness_commitment: attempt.witness
|
||||||
@ -1697,7 +1715,7 @@ RPC.prototype._tmpl = function _tmpl(version, coinbase, rules, callback) {
|
|||||||
: undefined
|
: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!coinbase) {
|
if (coinbase) {
|
||||||
template.coinbaseaux = undefined;
|
template.coinbaseaux = undefined;
|
||||||
template.coinbasevalue = undefined;
|
template.coinbasevalue = undefined;
|
||||||
tx = block.txs[0];
|
tx = block.txs[0];
|
||||||
@ -1742,8 +1760,9 @@ RPC.prototype._poll = function _poll(lpid, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RPC.prototype._clearBlock = function _clearBlock() {
|
RPC.prototype._clearBlock = function _clearBlock() {
|
||||||
this.currentBlock = null;
|
this.attempt = null;
|
||||||
this.blockStart = 0;
|
this.start = 0;
|
||||||
|
this.coinbase = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
RPC.prototype._bindChain = function _bindChain() {
|
RPC.prototype._bindChain = function _bindChain() {
|
||||||
@ -1755,7 +1774,7 @@ RPC.prototype._bindChain = function _bindChain() {
|
|||||||
this._boundChain = true;
|
this._boundChain = true;
|
||||||
|
|
||||||
this.chain.on('connect', function() {
|
this.chain.on('connect', function() {
|
||||||
if (!self.currentBlock)
|
if (!self.attempt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self._clearBlock();
|
self._clearBlock();
|
||||||
@ -1765,10 +1784,10 @@ RPC.prototype._bindChain = function _bindChain() {
|
|||||||
this.mempool.on('tx', function() {
|
this.mempool.on('tx', function() {
|
||||||
var diff;
|
var diff;
|
||||||
|
|
||||||
if (!self.currentBlock)
|
if (!self.attempt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
diff = utils.now() - self.blockStart;
|
diff = utils.now() - self.start;
|
||||||
|
|
||||||
if (diff > 5) {
|
if (diff > 5) {
|
||||||
self._clearBlock();
|
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 self = this;
|
||||||
|
var attempt = this.attempt;
|
||||||
|
|
||||||
this._bindChain();
|
this._bindChain();
|
||||||
|
|
||||||
if (this.currentBlock)
|
if (attempt) {
|
||||||
return callback(null, this.currentBlock);
|
attempt.updateNonce();
|
||||||
|
this.coinbase[attempt.block.merkleRoot] = attempt.coinbase.clone();
|
||||||
|
return callback(null, attempt);
|
||||||
|
}
|
||||||
|
|
||||||
this.miner.createBlock(function(err, attempt) {
|
this.miner.createBlock(function(err, attempt) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(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);
|
callback(null, attempt);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -2208,6 +2234,9 @@ RPC.prototype.signrawtransaction = function signrawtransaction(args, callback) {
|
|||||||
+ ' sighashtype )'));
|
+ ' sighashtype )'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!utils.isHex(args[0]))
|
||||||
|
return callback(new RPCError('Invalid parameter'));
|
||||||
|
|
||||||
raw = new Buffer(args[0], 'hex');
|
raw = new Buffer(args[0], 'hex');
|
||||||
p = new bcoin.reader(raw);
|
p = new bcoin.reader(raw);
|
||||||
txs = [];
|
txs = [];
|
||||||
|
|||||||
@ -88,6 +88,8 @@ HTTPServer.prototype._init = function _init() {
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.server.on('request', function(req, res) {
|
this.server.on('request', function(req, res) {
|
||||||
|
if (req.pathname === '/')
|
||||||
|
return;
|
||||||
self.logger.debug('Request for path=%s (%s).',
|
self.logger.debug('Request for path=%s (%s).',
|
||||||
req.pathname, req.socket.remoteAddress);
|
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 {
|
try {
|
||||||
self.rpc.execute(req.body, handle);
|
self.rpc.execute(req.body, handle);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -185,6 +185,24 @@ MinerBlock.prototype.updateCoinbase = function updateCoinbase() {
|
|||||||
output.value = this.block.getReward(this.network);
|
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
|
* Rebuild the merkle tree and update merkle root as well as the
|
||||||
* timestamp (also calls {@link MinerBlock#updateCommitment}
|
* timestamp (also calls {@link MinerBlock#updateCommitment}
|
||||||
@ -297,14 +315,7 @@ MinerBlock.prototype.findNonce = function findNonce() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Overflow the nonce and increment the extraNonce.
|
// Overflow the nonce and increment the extraNonce.
|
||||||
block.nonce = 0;
|
this.updateNonce();
|
||||||
this.extraNonce.iaddn(1);
|
|
||||||
|
|
||||||
// We incremented the extraNonce, need to update coinbase.
|
|
||||||
this.updateCoinbase();
|
|
||||||
|
|
||||||
// We changed the coinbase, need to update merkleRoot.
|
|
||||||
this.updateMerkle();
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user