refactor: peer. etc.
This commit is contained in:
parent
19e5359f0f
commit
63a9dc61f6
@ -928,6 +928,13 @@ Chain.prototype.reset = co(function* reset(height) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset the chain to the desired height without a lock.
|
||||
* @private
|
||||
* @param {Number} height
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Chain.prototype._reset = co(function* reset(height) {
|
||||
var result = yield this.db.reset(height);
|
||||
|
||||
@ -956,6 +963,13 @@ Chain.prototype.resetTime = co(function* resetTime(ts) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset the chain to the desired timestamp without a lock.
|
||||
* @private
|
||||
* @param {Number} ts - Timestamp.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Chain.prototype._resetTime = co(function* resetTime(ts) {
|
||||
var entry = yield this.byTime(ts);
|
||||
|
||||
@ -1003,6 +1017,13 @@ Chain.prototype.add = co(function* add(block) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a block to the chain without a lock.
|
||||
* @private
|
||||
* @param {Block|MerkleBlock|MemBlock} block
|
||||
* @param {Function} callback - Returns [{@link VerifyError}].
|
||||
*/
|
||||
|
||||
Chain.prototype._add = co(function* add(block) {
|
||||
var ret, initial, hash, prevBlock;
|
||||
var height, checkpoint, orphan, entry;
|
||||
@ -1017,7 +1038,8 @@ Chain.prototype._add = co(function* add(block) {
|
||||
hash = block.hash('hex');
|
||||
prevBlock = block.prevBlock;
|
||||
|
||||
this._mark();
|
||||
// Mark the start time.
|
||||
this.mark();
|
||||
|
||||
// Do not revalidate known invalid blocks.
|
||||
if (this.invalid[hash] || this.invalid[prevBlock]) {
|
||||
@ -1176,7 +1198,7 @@ Chain.prototype._add = co(function* add(block) {
|
||||
}
|
||||
|
||||
// Keep track of stats.
|
||||
this._done(block, entry);
|
||||
this.finish(block, entry);
|
||||
|
||||
// No orphan chain.
|
||||
if (!this.orphan.map[hash])
|
||||
@ -1225,7 +1247,7 @@ Chain.prototype._isSlow = function _isSlow() {
|
||||
* @private
|
||||
*/
|
||||
|
||||
Chain.prototype._mark = function _mark() {
|
||||
Chain.prototype.mark = function mark() {
|
||||
this._time = utils.hrtime();
|
||||
};
|
||||
|
||||
@ -1237,7 +1259,7 @@ Chain.prototype._mark = function _mark() {
|
||||
* @param {ChainEntry} entry
|
||||
*/
|
||||
|
||||
Chain.prototype._done = function _done(block, entry) {
|
||||
Chain.prototype.finish = function finish(block, entry) {
|
||||
var elapsed, time;
|
||||
|
||||
// Keep track of total blocks handled.
|
||||
@ -1500,6 +1522,13 @@ Chain.prototype.getLocator = co(function* getLocator(start) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Calculate chain locator without a lock.
|
||||
* @private
|
||||
* @param {(Number|Hash)?} start
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Chain.prototype._getLocator = co(function* getLocator(start) {
|
||||
var hashes = [];
|
||||
var step = 1;
|
||||
|
||||
@ -154,6 +154,14 @@ Mempool.prototype.addBlock = co(function* addBlock(block) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Notify the mempool that a new block
|
||||
* has come without a lock.
|
||||
* @private
|
||||
* @param {Block} block
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype._addBlock = co(function* addBlock(block) {
|
||||
var entries = [];
|
||||
var i, entry, tx, hash;
|
||||
@ -207,6 +215,14 @@ Mempool.prototype.removeBlock = co(function* removeBlock(block) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Notify the mempool that a block
|
||||
* has been disconnected without a lock.
|
||||
* @private
|
||||
* @param {Block} block
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype._removeBlock = co(function* removeBlock(block) {
|
||||
var i, entry, tx, hash;
|
||||
|
||||
@ -553,7 +569,7 @@ Mempool.prototype.addTX = co(function* addTX(tx) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a transaction to the mempool.
|
||||
* Add a transaction to the mempool without a lock.
|
||||
* @private
|
||||
* @param {TX} tx
|
||||
* @param {Function} callback - Returns [{@link VerifyError}].
|
||||
@ -688,6 +704,13 @@ Mempool.prototype.addUnchecked = co(function* addUnchecked(entry) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a transaction to the mempool without a lock.
|
||||
* @private
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {Function} callback - Returns [{@link VerifyError}].
|
||||
*/
|
||||
|
||||
Mempool.prototype._addUnchecked = co(function* addUnchecked(entry) {
|
||||
var i, resolved, tx, orphan;
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var bcoin = require('../env');
|
||||
var utils = require('../utils/utils');
|
||||
var spawn = require('../utils/spawn');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var packets = require('./packets');
|
||||
var assert = utils.assert;
|
||||
@ -247,7 +248,14 @@ BIP150.prototype.complete = function complete(err) {
|
||||
this.callback = null;
|
||||
};
|
||||
|
||||
BIP150.prototype.wait = function wait(timeout, callback) {
|
||||
BIP150.prototype.wait = function wait(timeout) {
|
||||
var self = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._wait(timeout, spawn.wrap(resolve, reject));
|
||||
});
|
||||
};
|
||||
|
||||
BIP150.prototype._wait = function wait(timeout, callback) {
|
||||
var self = this;
|
||||
|
||||
assert(!this.auth, 'Cannot wait for init after handshake.');
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var bcoin = require('../env');
|
||||
var utils = require('../utils/utils');
|
||||
var spawn = require('../utils/spawn');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var assert = utils.assert;
|
||||
var constants = bcoin.constants;
|
||||
@ -455,7 +456,19 @@ BIP151.prototype.complete = function complete(err) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
BIP151.prototype.wait = function wait(timeout, callback) {
|
||||
BIP151.prototype.wait = function wait(timeout) {
|
||||
var self = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._wait(timeout, spawn.wrap(resolve, reject));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a timeout and wait for handshake to complete.
|
||||
* @private
|
||||
*/
|
||||
|
||||
BIP151.prototype._wait = function wait(timeout, callback) {
|
||||
var self = this;
|
||||
|
||||
assert(!this.handshake, 'Cannot wait for init after handshake.');
|
||||
|
||||
@ -39,6 +39,7 @@ function CompactBlock(options) {
|
||||
this.count = 0;
|
||||
this.sipKey = null;
|
||||
this.timeout = null;
|
||||
this.callback = null;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
@ -362,12 +363,31 @@ CompactBlock.fromBlock = function fromBlock(block, nonce) {
|
||||
return new CompactBlock().fromBlock(block, nonce);
|
||||
};
|
||||
|
||||
CompactBlock.prototype.startTimeout = function startTimeout(time, callback) {
|
||||
assert(this.timeout == null);
|
||||
this.timeout = setTimeout(callback, time);
|
||||
CompactBlock.prototype.wait = function wait(callback) {
|
||||
var self = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
self._wait(time, spawn.wrap(resolve, reject));
|
||||
});
|
||||
};
|
||||
|
||||
CompactBlock.prototype.stopTimeout = function stopTimeout() {
|
||||
CompactBlock.prototype._wait = function wait(time, callback) {
|
||||
var self = this;
|
||||
assert(this.timeout == null);
|
||||
this.callback = callback;
|
||||
this.timeout = setTimeout(function() {
|
||||
self.complete(new Error('Timed out.'));
|
||||
}, time);
|
||||
};
|
||||
|
||||
CompactBlock.prototype.complete = function complete(err) {
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
this.callback(err);
|
||||
}
|
||||
};
|
||||
|
||||
CompactBlock.prototype.destroy = function destroy() {
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
|
||||
514
lib/net/peer.js
514
lib/net/peer.js
@ -179,10 +179,6 @@ Peer.uid = 0;
|
||||
Peer.prototype._init = function init() {
|
||||
var self = this;
|
||||
|
||||
this.socket.once('connect', function() {
|
||||
self._onConnect();
|
||||
});
|
||||
|
||||
this.socket.once('error', function(err) {
|
||||
self.error(err);
|
||||
|
||||
@ -229,11 +225,96 @@ Peer.prototype._init = function init() {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.connected) {
|
||||
utils.nextTick(function() {
|
||||
self._onConnect();
|
||||
});
|
||||
this.open();
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the socket and begin connecting. This method
|
||||
* will use `options.createSocket` if provided.
|
||||
* @param {String} host
|
||||
* @param {Number} port
|
||||
* @returns {net.Socket}
|
||||
*/
|
||||
|
||||
Peer.prototype.connect = function connect(port, host) {
|
||||
var self = this;
|
||||
var socket, proxy, net;
|
||||
|
||||
assert(!this.socket);
|
||||
|
||||
if (this.createSocket) {
|
||||
socket = this.createSocket(port, host);
|
||||
} else {
|
||||
if (utils.isBrowser) {
|
||||
proxy = require('./proxysocket');
|
||||
socket = proxy.connect(this.pool.proxyServer, port, host);
|
||||
} else {
|
||||
net = require('net');
|
||||
socket = net.connect(port, host);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.debug('Connecting to %s.', this.hostname);
|
||||
|
||||
socket.once('connect', function() {
|
||||
self.logger.info('Connected to %s.', self.hostname);
|
||||
});
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Open and initialize the peer.
|
||||
*/
|
||||
|
||||
Peer.prototype.open = co(function* open() {
|
||||
try {
|
||||
yield this._connect();
|
||||
yield this._bip151();
|
||||
yield this._bip150();
|
||||
yield this._handshake();
|
||||
yield this._finalize();
|
||||
} catch (e) {
|
||||
this.error(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally we can let the pool know
|
||||
// that this peer is ready to go.
|
||||
this.emit('open');
|
||||
});
|
||||
|
||||
/**
|
||||
* Wait for connection.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._connect = function _connect() {
|
||||
var self = this;
|
||||
|
||||
if (this.connected) {
|
||||
assert(!this.outbound);
|
||||
return spawn.wait();
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
self.socket.once('connect', function() {
|
||||
self.ts = utils.now();
|
||||
self.connected = true;
|
||||
self.emit('connect');
|
||||
|
||||
clearTimeout(self.connectTimeout);
|
||||
self.connectTimeout = null;
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
self.connectTimeout = setTimeout(function() {
|
||||
self.connectTimeout = null;
|
||||
reject(new Error('Connection timed out.'));
|
||||
self.ignore();
|
||||
}, 10000);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -242,96 +323,76 @@ Peer.prototype._init = function init() {
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._onConnect = function _onConnect() {
|
||||
var self = this;
|
||||
|
||||
this.ts = utils.now();
|
||||
this.connected = true;
|
||||
|
||||
this.emit('connect');
|
||||
|
||||
if (this.connectTimeout != null) {
|
||||
clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
}
|
||||
|
||||
Peer.prototype._bip151 = co(function* _bip151() {
|
||||
// Send encinit. Wait for handshake to complete.
|
||||
if (this.bip151) {
|
||||
assert(!this.bip151.completed);
|
||||
this.logger.info('Attempting BIP151 handshake (%s).', this.hostname);
|
||||
this.send(this.bip151.toEncinit());
|
||||
return this.bip151.wait(3000, function(err) {
|
||||
if (err)
|
||||
self.error(err, true);
|
||||
self._onBIP151();
|
||||
});
|
||||
}
|
||||
if (!this.bip151)
|
||||
return;
|
||||
|
||||
this._onBIP151();
|
||||
};
|
||||
assert(!this.bip151.completed);
|
||||
|
||||
this.logger.info('Attempting BIP151 handshake (%s).', this.hostname);
|
||||
|
||||
this.send(this.bip151.toEncinit());
|
||||
|
||||
try {
|
||||
yield this.bip151.wait(3000);
|
||||
} catch (err) {
|
||||
this.error(err, true);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle post bip151-handshake.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._onBIP151 = function _onBIP151() {
|
||||
var self = this;
|
||||
Peer.prototype._bip150 = co(function* _bip150() {
|
||||
if (!this.bip151)
|
||||
return;
|
||||
|
||||
if (this.bip151) {
|
||||
assert(this.bip151.completed);
|
||||
assert(this.bip151.completed);
|
||||
|
||||
if (this.bip151.handshake) {
|
||||
this.logger.info('BIP151 handshake complete (%s).', this.hostname);
|
||||
this.logger.info('Connection is encrypted (%s).', this.hostname);
|
||||
}
|
||||
|
||||
if (this.bip150) {
|
||||
assert(!this.bip150.completed);
|
||||
|
||||
if (!this.bip151.handshake)
|
||||
return this.error('BIP151 handshake was not completed for BIP150.');
|
||||
|
||||
this.logger.info('Attempting BIP150 handshake (%s).', this.hostname);
|
||||
|
||||
if (this.bip150.outbound) {
|
||||
if (!this.bip150.peerIdentity)
|
||||
return this.error('No known identity for peer.');
|
||||
this.send(this.bip150.toChallenge());
|
||||
}
|
||||
|
||||
return this.bip150.wait(3000, function(err) {
|
||||
if (err)
|
||||
return self.error(err);
|
||||
self._onHandshake();
|
||||
});
|
||||
}
|
||||
if (this.bip151.handshake) {
|
||||
this.logger.info('BIP151 handshake complete (%s).', this.hostname);
|
||||
this.logger.info('Connection is encrypted (%s).', this.hostname);
|
||||
}
|
||||
|
||||
this._onHandshake();
|
||||
};
|
||||
if (!this.bip150)
|
||||
return;
|
||||
|
||||
assert(!this.bip150.completed);
|
||||
|
||||
if (!this.bip151.handshake)
|
||||
throw new Error('BIP151 handshake was not completed for BIP150.');
|
||||
|
||||
this.logger.info('Attempting BIP150 handshake (%s).', this.hostname);
|
||||
|
||||
if (this.bip150.outbound) {
|
||||
if (!this.bip150.peerIdentity)
|
||||
return this.error('No known identity for peer.');
|
||||
this.send(this.bip150.toChallenge());
|
||||
}
|
||||
|
||||
yield this.bip150.wait(3000);
|
||||
|
||||
if (!this.bip150)
|
||||
return;
|
||||
|
||||
assert(this.bip150.completed);
|
||||
|
||||
if (this.bip150.auth) {
|
||||
this.logger.info('BIP150 handshake complete (%s).', this.hostname);
|
||||
this.logger.info('Peer is authed (%s): %s.',
|
||||
this.hostname, this.bip150.getAddress());
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle post handshake.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._onHandshake = function _onHandshake() {
|
||||
var self = this;
|
||||
|
||||
if (this.bip150) {
|
||||
assert(this.bip150.completed);
|
||||
if (this.bip150.auth) {
|
||||
this.logger.info('BIP150 handshake complete (%s).', this.hostname);
|
||||
this.logger.info('Peer is authed (%s): %s.',
|
||||
this.hostname, this.bip150.getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
this.request('verack', function(err) {
|
||||
self._onAck(err);
|
||||
});
|
||||
|
||||
Peer.prototype._handshake = co(function* _handshake() {
|
||||
// Say hello.
|
||||
this.sendVersion();
|
||||
|
||||
@ -341,32 +402,33 @@ Peer.prototype._onHandshake = function _onHandshake() {
|
||||
&& this.pool.server) {
|
||||
this.send(new packets.AddrPacket([this.pool.address]));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle `ack` event (called on verack).
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._onAck = function _onAck(err) {
|
||||
var self = this;
|
||||
|
||||
if (err) {
|
||||
this.error(err);
|
||||
return;
|
||||
}
|
||||
yield this.request('verack');
|
||||
|
||||
// Wait for _their_ version.
|
||||
if (!this.version) {
|
||||
this.logger.debug(
|
||||
'Peer sent a verack without a version (%s).',
|
||||
this.hostname);
|
||||
this.request('version', this._onAck.bind(this));
|
||||
return;
|
||||
|
||||
yield this.request('version');
|
||||
|
||||
assert(this.version);
|
||||
}
|
||||
|
||||
this.ack = true;
|
||||
|
||||
this.logger.debug('Received verack (%s).', this.hostname);
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `ack` event (called on verack).
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._finalize = co(function* _finalize() {
|
||||
var self = this;
|
||||
|
||||
// Setup the ping interval.
|
||||
this.pingTimeout = setInterval(function() {
|
||||
self.sendPing();
|
||||
@ -407,53 +469,7 @@ Peer.prototype._onAck = function _onAck(err) {
|
||||
|
||||
// Start syncing the chain.
|
||||
this.sync();
|
||||
|
||||
this.logger.debug('Received verack (%s).', this.hostname);
|
||||
|
||||
// Finally we can let the pool know
|
||||
// that this peer is ready to go.
|
||||
this.emit('ack');
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the socket and begin connecting. This method
|
||||
* will use `options.createSocket` if provided.
|
||||
* @param {String} host
|
||||
* @param {Number} port
|
||||
* @returns {net.Socket}
|
||||
*/
|
||||
|
||||
Peer.prototype.connect = function connect(port, host) {
|
||||
var self = this;
|
||||
var socket, proxy, net;
|
||||
|
||||
assert(!this.socket);
|
||||
|
||||
if (this.createSocket) {
|
||||
socket = this.createSocket(port, host);
|
||||
} else {
|
||||
if (utils.isBrowser) {
|
||||
proxy = require('./proxysocket');
|
||||
socket = proxy.connect(this.pool.proxyServer, port, host);
|
||||
} else {
|
||||
net = require('net');
|
||||
socket = net.connect(port, host);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.debug('Connecting to %s.', this.hostname);
|
||||
|
||||
socket.once('connect', function() {
|
||||
self.logger.info('Connected to %s.', self.hostname);
|
||||
});
|
||||
|
||||
this.connectTimeout = setTimeout(function() {
|
||||
self.error('Connection timed out.');
|
||||
self.ignore();
|
||||
}, 10000);
|
||||
|
||||
return socket;
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Test whether the peer is the loader peer.
|
||||
@ -604,6 +620,7 @@ Peer.prototype.sendVersion = function sendVersion() {
|
||||
height: this.chain.height,
|
||||
relay: this.options.relay
|
||||
});
|
||||
|
||||
this.send(packet);
|
||||
};
|
||||
|
||||
@ -678,7 +695,7 @@ Peer.prototype.sendFeeRate = function sendFeeRate(rate) {
|
||||
*/
|
||||
|
||||
Peer.prototype.destroy = function destroy() {
|
||||
var i, j, keys, cmd, queue;
|
||||
var i, j, keys, cmd, queue, hash;
|
||||
|
||||
if (this.destroyed)
|
||||
return;
|
||||
@ -715,6 +732,13 @@ Peer.prototype.destroy = function destroy() {
|
||||
queue[j].destroy();
|
||||
}
|
||||
|
||||
keys = Object.keys(this.compactBlocks);
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
hash = keys[i];
|
||||
this.compactBlocks[hash].destroy();
|
||||
}
|
||||
|
||||
this.emit('close');
|
||||
};
|
||||
|
||||
@ -797,20 +821,21 @@ Peer.prototype.error = function error(err, keep) {
|
||||
* Executed on timeout or once packet is received.
|
||||
*/
|
||||
|
||||
Peer.prototype.request = function request(cmd, callback) {
|
||||
var entry;
|
||||
Peer.prototype.request = function request(cmd) {
|
||||
var self = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
var entry;
|
||||
|
||||
if (this.destroyed)
|
||||
return callback(new Error('Destroyed'));
|
||||
if (self.destroyed)
|
||||
return reject(new Error('Destroyed'));
|
||||
|
||||
entry = new RequestEntry(this, cmd, callback);
|
||||
entry = new RequestEntry(self, cmd, resolve, reject);
|
||||
|
||||
if (!this.requestMap[cmd])
|
||||
this.requestMap[cmd] = [];
|
||||
if (!self.requestMap[cmd])
|
||||
self.requestMap[cmd] = [];
|
||||
|
||||
this.requestMap[cmd].push(entry);
|
||||
|
||||
return entry;
|
||||
self.requestMap[cmd].push(entry);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -832,7 +857,7 @@ Peer.prototype.response = function response(cmd, payload) {
|
||||
if (!entry)
|
||||
return false;
|
||||
|
||||
res = entry.callback(null, payload, cmd);
|
||||
res = entry.resolve(payload);
|
||||
|
||||
if (res === false)
|
||||
return false;
|
||||
@ -1114,11 +1139,19 @@ Peer.prototype._handleGetUTXOs = co(function* _handleGetUTXOs(packet) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this.__handleGetUTXOs(packet);
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `getheaders` packet without lock.
|
||||
* @private
|
||||
* @param {GetHeadersPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype.__handleGetUTXOs = co(function* _handleGetUTXOs(packet) {
|
||||
var i, utxos, prevout, hash, index, coin;
|
||||
|
||||
@ -1142,12 +1175,7 @@ Peer.prototype.__handleGetUTXOs = co(function* _handleGetUTXOs(packet) {
|
||||
index = prevout.index;
|
||||
|
||||
if (this.mempool && packet.mempool) {
|
||||
try {
|
||||
coin = this.mempool.getCoin(hash, index);
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
return;
|
||||
}
|
||||
coin = this.mempool.getCoin(hash, index);
|
||||
|
||||
if (coin) {
|
||||
utxos.hits.push(1);
|
||||
@ -1161,12 +1189,7 @@ Peer.prototype.__handleGetUTXOs = co(function* _handleGetUTXOs(packet) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
coin = yield this.chain.db.getCoin(hash, index);
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
return;
|
||||
}
|
||||
coin = yield this.chain.db.getCoin(hash, index);
|
||||
|
||||
if (!coin) {
|
||||
utxos.hits.push(0);
|
||||
@ -1203,12 +1226,20 @@ Peer.prototype._handleHaveWitness = function _handleHaveWitness(packet) {
|
||||
Peer.prototype._handleGetHeaders = co(function* _handleGetHeaders(packet) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return this.__handleGetHeaders(packet);
|
||||
return yield this.__handleGetHeaders(packet);
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `getheaders` packet without lock.
|
||||
* @private
|
||||
* @param {GetHeadersPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype.__handleGetHeaders = co(function* _handleGetHeaders(packet) {
|
||||
var headers = [];
|
||||
var hash, entry;
|
||||
@ -1260,12 +1291,20 @@ Peer.prototype.__handleGetHeaders = co(function* _handleGetHeaders(packet) {
|
||||
Peer.prototype._handleGetBlocks = co(function* _handleGetBlocks(packet) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return this.__handleGetBlocks(packet);
|
||||
return yield this.__handleGetBlocks(packet);
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `getblocks` packet without lock.
|
||||
* @private
|
||||
* @param {GetBlocksPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype.__handleGetBlocks = co(function* _handleGetBlocks(packet) {
|
||||
var blocks = [];
|
||||
var hash;
|
||||
@ -1310,7 +1349,7 @@ Peer.prototype.__handleGetBlocks = co(function* _handleGetBlocks(packet) {
|
||||
* @param {VersionPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype._handleVersion = function _handleVersion(version) {
|
||||
Peer.prototype._handleVersion = co(function* _handleVersion(version) {
|
||||
var self = this;
|
||||
|
||||
if (!this.network.selfConnect) {
|
||||
@ -1352,43 +1391,33 @@ Peer.prototype._handleVersion = function _handleVersion(version) {
|
||||
}
|
||||
|
||||
if (this.options.witness) {
|
||||
if (!version.hasWitness()) {
|
||||
this.haveWitness = version.hasWitness();
|
||||
|
||||
if (!this.haveWitness) {
|
||||
if (!this.network.oldWitness) {
|
||||
this.error('Peer does not support segregated witness.');
|
||||
this.ignore();
|
||||
return;
|
||||
}
|
||||
return this.request('havewitness', function(err) {
|
||||
if (err) {
|
||||
self.error('Peer does not support segregated witness.');
|
||||
self.ignore();
|
||||
return;
|
||||
}
|
||||
self._finishVersion(version);
|
||||
});
|
||||
|
||||
try {
|
||||
yield this.request('havewitness');
|
||||
} catch (err) {
|
||||
this.error('Peer does not support segregated witness.');
|
||||
this.ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
this.haveWitness = true;
|
||||
}
|
||||
}
|
||||
|
||||
this._finishVersion(version);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finish handling `version` packet.
|
||||
* @private
|
||||
* @param {VersionPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype._finishVersion = function _finishVersion(version) {
|
||||
if (version.hasWitness())
|
||||
this.haveWitness = true;
|
||||
|
||||
if (!version.relay)
|
||||
this.relay = false;
|
||||
this.relay = version.relay;
|
||||
this.version = version;
|
||||
|
||||
this.send(new packets.VerackPacket());
|
||||
this.version = version;
|
||||
this.fire('version', version);
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `verack` packet.
|
||||
@ -1407,7 +1436,6 @@ Peer.prototype._handleVerack = function _handleVerack(packet) {
|
||||
*/
|
||||
|
||||
Peer.prototype._handleMempool = function _handleMempool(packet) {
|
||||
var self = this;
|
||||
var items = [];
|
||||
var i, hashes;
|
||||
|
||||
@ -1425,9 +1453,9 @@ Peer.prototype._handleMempool = function _handleMempool(packet) {
|
||||
for (i = 0; i < hashes.length; i++)
|
||||
items.push(new InvItem(constants.inv.TX, hashes[i]));
|
||||
|
||||
self.logger.debug('Sending mempool snapshot (%s).', self.hostname);
|
||||
this.logger.debug('Sending mempool snapshot (%s).', this.hostname);
|
||||
|
||||
self.sendInv(items);
|
||||
this.sendInv(items);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1490,11 +1518,19 @@ Peer.prototype._handleGetData = co(function* _handleGetData(packet) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this.__handleGetData(packet);
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `getdata` packet without lock.
|
||||
* @private
|
||||
* @param {GetDataPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype._handleGetData = co(function* _handleGetData(packet) {
|
||||
var notFound = [];
|
||||
var items = packet.items;
|
||||
@ -2032,8 +2068,7 @@ Peer.prototype._handleSendCmpct = function _handleSendCmpct(packet) {
|
||||
* @param {CmpctBlockPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(packet) {
|
||||
var self = this;
|
||||
Peer.prototype._handleCmpctBlock = co(function* _handleCmpctBlock(packet) {
|
||||
var block = packet.block;
|
||||
var hash = block.hash('hex');
|
||||
var result;
|
||||
@ -2075,13 +2110,16 @@ Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(packet) {
|
||||
'Received semi-full compact block %s (%s).',
|
||||
block.rhash, this.hostname);
|
||||
|
||||
block.startTimeout(10000, function() {
|
||||
self.logger.debug(
|
||||
try {
|
||||
yield block.wait(10000);
|
||||
} catch (e) {
|
||||
this.logger.debug(
|
||||
'Compact block timed out: %s (%s).',
|
||||
block.rhash, self.hostname);
|
||||
delete self.compactBlocks[hash];
|
||||
});
|
||||
};
|
||||
block.rhash, this.hostname);
|
||||
|
||||
delete this.compactBlocks[hash];
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `getblocktxn` packet.
|
||||
@ -2089,18 +2127,9 @@ Peer.prototype._handleCmpctBlock = function _handleCmpctBlock(packet) {
|
||||
* @param {GetBlockTxnPacket}
|
||||
*/
|
||||
|
||||
Peer.prototype._handleGetBlockTxn = function _handleGetBlockTxn(packet) {
|
||||
var self = this;
|
||||
Peer.prototype._handleGetBlockTxn = co(function* _handleGetBlockTxn(packet) {
|
||||
var req = packet.request;
|
||||
var res, item;
|
||||
|
||||
function done(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
self.fire('blocktxn', req);
|
||||
}
|
||||
var res, item, block;
|
||||
|
||||
if (this.chain.db.options.spv)
|
||||
return done();
|
||||
@ -2113,32 +2142,28 @@ Peer.prototype._handleGetBlockTxn = function _handleGetBlockTxn(packet) {
|
||||
|
||||
item = new InvItem(constants.inv.BLOCK, req.hash);
|
||||
|
||||
this._getItem(item, function(err, block) {
|
||||
if (err)
|
||||
return done(err);
|
||||
block = yield this._getItem(item);
|
||||
|
||||
if (!block) {
|
||||
self.logger.debug(
|
||||
'Peer sent getblocktxn for non-existent block (%s).',
|
||||
self.hostname);
|
||||
self.setMisbehavior(100);
|
||||
return done();
|
||||
}
|
||||
if (!block) {
|
||||
this.logger.debug(
|
||||
'Peer sent getblocktxn for non-existent block (%s).',
|
||||
this.hostname);
|
||||
this.setMisbehavior(100);
|
||||
return;
|
||||
}
|
||||
|
||||
if (block.height < self.chain.tip.height - 15) {
|
||||
self.logger.debug(
|
||||
'Peer sent a getblocktxn for a block > 15 deep (%s)',
|
||||
self.hostname);
|
||||
return done();
|
||||
}
|
||||
if (block.height < this.chain.tip.height - 15) {
|
||||
this.logger.debug(
|
||||
'Peer sent a getblocktxn for a block > 15 deep (%s)',
|
||||
this.hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
res = bcoin.bip152.TXResponse.fromBlock(block, req);
|
||||
res = bcoin.bip152.TXResponse.fromBlock(block, req);
|
||||
|
||||
self.send(new packets.BlockTxnPacket(res, false));
|
||||
|
||||
done();
|
||||
});
|
||||
};
|
||||
this.send(new packets.BlockTxnPacket(res, false));
|
||||
this.fire('blocktxn', req);
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `blocktxn` packet.
|
||||
@ -2155,9 +2180,8 @@ Peer.prototype._handleBlockTxn = function _handleBlockTxn(packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fire('getblocktxn', res);
|
||||
block.complete();
|
||||
|
||||
block.stopTimeout();
|
||||
delete this.compactBlocks[res.hash];
|
||||
|
||||
if (!block.fillMissing(res)) {
|
||||
@ -2171,6 +2195,7 @@ Peer.prototype._handleBlockTxn = function _handleBlockTxn(packet) {
|
||||
block.rhash, this.hostname);
|
||||
|
||||
this.fire('block', block.toBlock());
|
||||
this.fire('getblocktxn', res);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2461,10 +2486,11 @@ Peer.prototype.inspect = function inspect() {
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
function RequestEntry(peer, cmd, callback) {
|
||||
function RequestEntry(peer, cmd, resolve, reject) {
|
||||
this.peer = peer;
|
||||
this.cmd = cmd;
|
||||
this.callback = callback;
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
this.id = peer.uid++;
|
||||
this.onTimeout = this._onTimeout.bind(this);
|
||||
this.timeout = setTimeout(this.onTimeout, this.peer.requestTimeout);
|
||||
@ -2479,7 +2505,7 @@ RequestEntry.prototype._onTimeout = function _onTimeout() {
|
||||
if (utils.binaryRemove(queue, this, compare)) {
|
||||
if (queue.length === 0)
|
||||
delete this.peer.requestMap[this.cmd];
|
||||
this.callback(new Error('Timed out: ' + this.cmd));
|
||||
this.reject(new Error('Timed out: ' + this.cmd));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1006,7 +1006,7 @@ Pool.prototype.createPeer = function createPeer(addr, socket) {
|
||||
var self = this;
|
||||
var peer = new bcoin.peer(this, addr, socket);
|
||||
|
||||
peer.once('ack', function() {
|
||||
peer.once('open', function() {
|
||||
if (!peer.outbound)
|
||||
return;
|
||||
|
||||
|
||||
@ -384,7 +384,7 @@ TXDB.prototype.getInfo = function getInfo(tx) {
|
||||
* @param {Function} callback - Returns [Error, Buffer].
|
||||
*/
|
||||
|
||||
TXDB.prototype._addOrphan = co(function* _addOrphan(prevout, spender) {
|
||||
TXDB.prototype.addOrphan = co(function* addOrphan(prevout, spender) {
|
||||
var p = new BufferWriter();
|
||||
var key = layout.o(prevout.hash, prevout.index);
|
||||
var data = yield this.get(key);
|
||||
@ -405,7 +405,7 @@ TXDB.prototype._addOrphan = co(function* _addOrphan(prevout, spender) {
|
||||
* @param {Function} callback - Returns [Error, {@link Orphan}].
|
||||
*/
|
||||
|
||||
TXDB.prototype._getOrphans = co(function* _getOrphans(hash, index) {
|
||||
TXDB.prototype.getOrphans = co(function* getOrphans(hash, index) {
|
||||
var items = [];
|
||||
var i, data, orphans, orphan, tx, p;
|
||||
|
||||
@ -438,7 +438,7 @@ TXDB.prototype._getOrphans = co(function* _getOrphans(hash, index) {
|
||||
* @param {Function} callback - Returns [Error].
|
||||
*/
|
||||
|
||||
TXDB.prototype._verify = co(function* _verify(tx, info) {
|
||||
TXDB.prototype.verify = co(function* verify(tx, info) {
|
||||
var i, input, prevout, address, coin, spent, rtx, rinfo, result;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
@ -494,7 +494,7 @@ TXDB.prototype._verify = co(function* _verify(tx, info) {
|
||||
this.logger.warning('Removing conflicting tx: %s.',
|
||||
utils.revHex(spent.hash));
|
||||
|
||||
result = yield this._removeConflict(spent.hash, tx);
|
||||
result = yield this.removeConflict(spent.hash, tx);
|
||||
|
||||
// Spender was not removed, the current
|
||||
// transaction is not elligible to be added.
|
||||
@ -519,11 +519,11 @@ TXDB.prototype._verify = co(function* _verify(tx, info) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
TXDB.prototype._resolveOrphans = co(function* _resolveOrphans(tx, index) {
|
||||
TXDB.prototype.resolveOrphans = co(function* resolveOrphans(tx, index) {
|
||||
var hash = tx.hash('hex');
|
||||
var i, orphans, coin, item, input, orphan;
|
||||
|
||||
orphans = yield this._getOrphans(hash, index);
|
||||
orphans = yield this.getOrphans(hash, index);
|
||||
|
||||
if (!orphans)
|
||||
return false;
|
||||
@ -554,7 +554,7 @@ TXDB.prototype._resolveOrphans = co(function* _resolveOrphans(tx, index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
yield this._lazyRemove(orphan);
|
||||
yield this.lazyRemove(orphan);
|
||||
}
|
||||
|
||||
// Just going to be added again outside.
|
||||
@ -564,9 +564,7 @@ TXDB.prototype._resolveOrphans = co(function* _resolveOrphans(tx, index) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Add transaction, runs _confirm (separate batch) and
|
||||
* verify (separate batch for double spenders).
|
||||
* @private
|
||||
* Add transaction, runs `confirm()` and `verify()`.
|
||||
* @param {TX} tx
|
||||
* @param {PathInfo} info
|
||||
* @param {Function} callback
|
||||
@ -575,13 +573,21 @@ TXDB.prototype._resolveOrphans = co(function* _resolveOrphans(tx, index) {
|
||||
TXDB.prototype.add = co(function* add(tx, info) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this.addl(tx, info);
|
||||
return yield this._add(tx, info);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
TXDB.prototype.addl = co(function* add(tx, info) {
|
||||
/**
|
||||
* Add transaction without a lock.
|
||||
* @private
|
||||
* @param {TX} tx
|
||||
* @param {PathInfo} info
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
TXDB.prototype._add = co(function* add(tx, info) {
|
||||
var hash, path, account;
|
||||
var i, result, input, output, coin;
|
||||
var prevout, key, address, spender, orphans;
|
||||
@ -589,14 +595,14 @@ TXDB.prototype.addl = co(function* add(tx, info) {
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to wallet.');
|
||||
|
||||
// Attempt to confirm tx before adding it.
|
||||
result = yield this._confirm(tx, info);
|
||||
result = yield this.confirm(tx, info);
|
||||
|
||||
// Ignore if we already have this tx.
|
||||
if (result)
|
||||
return true;
|
||||
|
||||
// Verify and get coins.
|
||||
result = yield this._verify(tx, info);
|
||||
result = yield this.verify(tx, info);
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
@ -647,7 +653,7 @@ TXDB.prototype.addl = co(function* add(tx, info) {
|
||||
// Add orphan, if no parent transaction is yet known
|
||||
if (!input.coin) {
|
||||
try {
|
||||
yield this._addOrphan(prevout, spender);
|
||||
yield this.addOrphan(prevout, spender);
|
||||
} catch (e) {
|
||||
this.drop();
|
||||
throw e;
|
||||
@ -676,7 +682,7 @@ TXDB.prototype.addl = co(function* add(tx, info) {
|
||||
continue;
|
||||
|
||||
try {
|
||||
orphans = yield this._resolveOrphans(tx, i);
|
||||
orphans = yield this.resolveOrphans(tx, i);
|
||||
} catch (e) {
|
||||
this.drop();
|
||||
throw e;
|
||||
@ -720,7 +726,7 @@ TXDB.prototype.addl = co(function* add(tx, info) {
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
*/
|
||||
|
||||
TXDB.prototype._removeConflict = co(function* _removeConflict(hash, ref) {
|
||||
TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) {
|
||||
var tx = yield this.getTX(hash);
|
||||
var info;
|
||||
|
||||
@ -749,7 +755,7 @@ TXDB.prototype._removeConflict = co(function* _removeConflict(hash, ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
info = yield this._removeRecursive(tx);
|
||||
info = yield this.removeRecursive(tx);
|
||||
|
||||
return [tx, info];
|
||||
});
|
||||
@ -762,7 +768,7 @@ TXDB.prototype._removeConflict = co(function* _removeConflict(hash, ref) {
|
||||
* @param {Function} callback - Returns [Error, Boolean].
|
||||
*/
|
||||
|
||||
TXDB.prototype._removeRecursive = co(function* _removeRecursive(tx) {
|
||||
TXDB.prototype.removeRecursive = co(function* removeRecursive(tx) {
|
||||
var hash = tx.hash('hex');
|
||||
var i, spent, stx, info;
|
||||
|
||||
@ -777,14 +783,14 @@ TXDB.prototype._removeRecursive = co(function* _removeRecursive(tx) {
|
||||
if (!stx)
|
||||
throw new Error('Could not find spender.');
|
||||
|
||||
yield this._removeRecursive(stx);
|
||||
yield this.removeRecursive(stx);
|
||||
}
|
||||
|
||||
this.start();
|
||||
|
||||
// Remove the spender.
|
||||
try {
|
||||
info = yield this._lazyRemove(tx);
|
||||
info = yield this.lazyRemove(tx);
|
||||
} catch (e) {
|
||||
this.drop();
|
||||
throw e;
|
||||
@ -848,7 +854,7 @@ TXDB.prototype.isSpent = co(function* isSpent(hash, index) {
|
||||
* transaction was confirmed, or should be ignored.
|
||||
*/
|
||||
|
||||
TXDB.prototype._confirm = co(function* _confirm(tx, info) {
|
||||
TXDB.prototype.confirm = co(function* confirm(tx, info) {
|
||||
var hash = tx.hash('hex');
|
||||
var i, account, existing, output, coin;
|
||||
var address, key;
|
||||
@ -945,20 +951,27 @@ TXDB.prototype._confirm = co(function* _confirm(tx, info) {
|
||||
TXDB.prototype.remove = co(function* remove(hash) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this.removel(hash);
|
||||
return yield this._remove(hash);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
TXDB.prototype.removel = co(function* remove(hash) {
|
||||
/**
|
||||
* Remove a transaction without a lock.
|
||||
* @private
|
||||
* @param {Hash} hash
|
||||
* @param {Function} callback - Returns [Error].
|
||||
*/
|
||||
|
||||
TXDB.prototype._remove = co(function* remove(hash) {
|
||||
var tx = yield this.getTX(hash);
|
||||
var info;
|
||||
|
||||
if (!tx)
|
||||
return;
|
||||
|
||||
info = yield this._removeRecursive(tx);
|
||||
info = yield this.removeRecursive(tx);
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
@ -974,12 +987,12 @@ TXDB.prototype.removel = co(function* remove(hash) {
|
||||
* @param {Function} callback - Returns [Error].
|
||||
*/
|
||||
|
||||
TXDB.prototype._lazyRemove = co(function* lazyRemove(tx) {
|
||||
TXDB.prototype.lazyRemove = co(function* lazyRemove(tx) {
|
||||
var info = yield this.getInfo(tx);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
return yield this._remove(tx, info);
|
||||
return yield this.__remove(tx, info);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -990,7 +1003,7 @@ TXDB.prototype._lazyRemove = co(function* lazyRemove(tx) {
|
||||
* @param {Function} callback - Returns [Error].
|
||||
*/
|
||||
|
||||
TXDB.prototype._remove = co(function* remove(tx, info) {
|
||||
TXDB.prototype.__remove = co(function* remove(tx, info) {
|
||||
var hash = tx.hash('hex');
|
||||
var i, path, account, key, prevout;
|
||||
var address, input, output, coin;
|
||||
@ -1080,13 +1093,20 @@ TXDB.prototype._remove = co(function* remove(tx, info) {
|
||||
TXDB.prototype.unconfirm = co(function* unconfirm(hash) {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this.unconfirml(hash);
|
||||
return yield this._unconfirm(hash);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
TXDB.prototype.unconfirml = co(function* unconfirm(hash) {
|
||||
/**
|
||||
* Unconfirm a transaction without a lock.
|
||||
* @private
|
||||
* @param {Hash} hash
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
TXDB.prototype._unconfirm = co(function* unconfirm(hash) {
|
||||
var tx = yield this.getTX(hash);
|
||||
var info, result;
|
||||
|
||||
@ -1101,7 +1121,7 @@ TXDB.prototype.unconfirml = co(function* unconfirm(hash) {
|
||||
this.start();
|
||||
|
||||
try {
|
||||
result = yield this._unconfirm(tx, info);
|
||||
result = yield this.__unconfirm(tx, info);
|
||||
} catch (e) {
|
||||
this.drop();
|
||||
throw e;
|
||||
@ -1119,7 +1139,7 @@ TXDB.prototype.unconfirml = co(function* unconfirm(hash) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
TXDB.prototype._unconfirm = co(function* unconfirm(tx, info) {
|
||||
TXDB.prototype.__unconfirm = co(function* unconfirm(tx, info) {
|
||||
var hash = tx.hash('hex');
|
||||
var height = tx.height;
|
||||
var i, account, output, key, coin;
|
||||
@ -1613,8 +1633,10 @@ TXDB.prototype.getAccountCoins = co(function* getCoins(account) {
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
key = hashes[i];
|
||||
coin = yield this.getCoin(key[0], key[1]);
|
||||
|
||||
if (!coin)
|
||||
continue;
|
||||
|
||||
coins.push(coin);
|
||||
}
|
||||
|
||||
@ -1921,6 +1943,7 @@ TXDB.prototype.getAccountBalance = co(function* getBalance(account) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Zap pending transactions older than `age`.
|
||||
* @param {Number?} account
|
||||
* @param {Number} age - Age delta (delete transactions older than `now - age`).
|
||||
* @param {Function} callback
|
||||
@ -1935,6 +1958,14 @@ TXDB.prototype.zap = co(function* zap(account, age) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Zap pending transactions without a lock.
|
||||
* @private
|
||||
* @param {Number?} account
|
||||
* @param {Number} age
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
TXDB.prototype._zap = co(function* zap(account, age) {
|
||||
var i, txs, tx, hash;
|
||||
|
||||
@ -1953,7 +1984,7 @@ TXDB.prototype._zap = co(function* zap(account, age) {
|
||||
if (tx.ts !== 0)
|
||||
continue;
|
||||
|
||||
yield this.removel(hash);
|
||||
yield this._remove(hash);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -236,6 +236,13 @@ Wallet.prototype.addKey = co(function* addKey(account, key) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a public account key to the wallet without a lock.
|
||||
* @private
|
||||
* @param {HDPublicKey} key
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype._addKey = co(function* addKey(account, key) {
|
||||
var result;
|
||||
|
||||
@ -255,7 +262,7 @@ Wallet.prototype._addKey = co(function* addKey(account, key) {
|
||||
this.start();
|
||||
|
||||
try {
|
||||
result = yield account.addKey(key, true);
|
||||
result = yield account.addKey(key);
|
||||
} catch (e) {
|
||||
this.drop();
|
||||
throw e;
|
||||
@ -268,7 +275,6 @@ Wallet.prototype._addKey = co(function* addKey(account, key) {
|
||||
|
||||
/**
|
||||
* Remove a public account key from the wallet (multisig).
|
||||
* Remove the key from the wallet database.
|
||||
* @param {HDPublicKey} key
|
||||
* @param {Function} callback
|
||||
*/
|
||||
@ -282,6 +288,13 @@ Wallet.prototype.removeKey = co(function* removeKey(account, key) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove a public account key from the wallet (multisig).
|
||||
* @private
|
||||
* @param {HDPublicKey} key
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype._removeKey = co(function* removeKey(account, key) {
|
||||
var result;
|
||||
|
||||
@ -301,7 +314,7 @@ Wallet.prototype._removeKey = co(function* removeKey(account, key) {
|
||||
this.start();
|
||||
|
||||
try {
|
||||
result = yield account.removeKey(key, true);
|
||||
result = yield account.removeKey(key);
|
||||
} catch (e) {
|
||||
this.drop();
|
||||
throw e;
|
||||
@ -328,6 +341,14 @@ Wallet.prototype.setPassphrase = co(function* setPassphrase(old, new_) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Change or set master key's passphrase without a lock.
|
||||
* @private
|
||||
* @param {(String|Buffer)?} old
|
||||
* @param {String|Buffer} new_
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype._setPassphrase = co(function* setPassphrase(old, new_) {
|
||||
if (new_ == null) {
|
||||
new_ = old;
|
||||
@ -361,6 +382,13 @@ Wallet.prototype.retoken = co(function* retoken(passphrase) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Generate a new token without a lock.
|
||||
* @private
|
||||
* @param {(String|Buffer)?} passphrase
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype._retoken = co(function* retoken(passphrase) {
|
||||
var master = yield this.unlock(passphrase);
|
||||
|
||||
@ -463,6 +491,12 @@ Wallet.prototype.createAccount = co(function* createAccount(options) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Create an account without a lock.
|
||||
* @param {Object} options - See {@link Account} options.
|
||||
* @param {Function} callback - Returns [Error, {@link Account}].
|
||||
*/
|
||||
|
||||
Wallet.prototype._createAccount = co(function* createAccount(options) {
|
||||
var passphrase = options.passphrase;
|
||||
var timeout = options.timeout;
|
||||
@ -618,6 +652,13 @@ Wallet.prototype.createAddress = co(function* createAddress(account, change) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new address (increments depth) without a lock.
|
||||
* @param {(Number|String)?} account
|
||||
* @param {Boolean} change
|
||||
* @param {Function} callback - Returns [Error, {@link KeyRing}].
|
||||
*/
|
||||
|
||||
Wallet.prototype._createAddress = co(function* createAddress(account, change) {
|
||||
var result;
|
||||
|
||||
@ -763,6 +804,15 @@ Wallet.prototype.importKey = co(function* importKey(account, ring, passphrase) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Import a keyring (will not exist on derivation chain) without a lock.
|
||||
* @private
|
||||
* @param {(String|Number)?} account
|
||||
* @param {KeyRing} ring
|
||||
* @param {(String|Buffer)?} passphrase
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Wallet.prototype._importKey = co(function* importKey(account, ring, passphrase) {
|
||||
var exists, raw, path;
|
||||
|
||||
@ -847,7 +897,14 @@ Wallet.prototype.fund = co(function* fund(tx, options, force) {
|
||||
}
|
||||
});
|
||||
|
||||
Wallet.prototype._fund = co(function* fund(tx, options, force) {
|
||||
/**
|
||||
* Fill a transaction with inputs without a lock.
|
||||
* @private
|
||||
* @see MTX#selectCoins
|
||||
* @see MTX#fill
|
||||
*/
|
||||
|
||||
Wallet.prototype._fund = co(function* fund(tx, options) {
|
||||
var rate, account, coins;
|
||||
|
||||
if (!options)
|
||||
@ -968,6 +1025,14 @@ Wallet.prototype.send = co(function* send(options) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Build and send a transaction without a lock.
|
||||
* @private
|
||||
* @param {Object} options - See {@link Wallet#fund options}.
|
||||
* @param {Object[]} options.outputs - See {@link MTX#addOutput}.
|
||||
* @param {Function} callback - Returns [Error, {@link TX}].
|
||||
*/
|
||||
|
||||
Wallet.prototype._send = co(function* send(options) {
|
||||
var tx = yield this.createTX(options, true);
|
||||
|
||||
@ -1144,6 +1209,13 @@ Wallet.prototype.syncOutputDepth = co(function* syncOutputDepth(info) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Sync address depths without a lock.
|
||||
* @private
|
||||
* @param {PathInfo} info
|
||||
* @param {Function} callback - Returns [Error, Boolean]
|
||||
*/
|
||||
|
||||
Wallet.prototype._syncOutputDepth = co(function* syncOutputDepth(info) {
|
||||
var receive = [];
|
||||
var accounts = {};
|
||||
@ -1300,7 +1372,7 @@ Wallet.prototype.template = co(function* template(tx) {
|
||||
*/
|
||||
|
||||
Wallet.prototype.sign = co(function* sign(tx, options) {
|
||||
var passphrase, timeout, master, rings;
|
||||
var master, rings;
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
@ -1308,10 +1380,8 @@ Wallet.prototype.sign = co(function* sign(tx, options) {
|
||||
if (typeof options === 'string' || Buffer.isBuffer(options))
|
||||
options = { passphrase: options };
|
||||
|
||||
passphrase = options.passphrase;
|
||||
timeout = options.timeout;
|
||||
master = yield this.unlock(options.passphrase, options.timeout);
|
||||
|
||||
master = yield this.unlock(passphrase, timeout);
|
||||
rings = yield this.deriveInputs(tx);
|
||||
|
||||
return yield this.signAsync(rings, tx);
|
||||
@ -1991,6 +2061,14 @@ MasterKey.prototype.unlock = co(function* _unlock(passphrase, timeout) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Decrypt the key without a lock.
|
||||
* @private
|
||||
* @param {Buffer|String} passphrase - Zero this yourself.
|
||||
* @param {Number} [timeout=60000] timeout in ms.
|
||||
* @param {Function} callback - Returns [Error, {@link HDPrivateKey}].
|
||||
*/
|
||||
|
||||
MasterKey.prototype._unlock = co(function* _unlock(passphrase, timeout) {
|
||||
var data, key;
|
||||
|
||||
@ -2046,6 +2124,13 @@ MasterKey.prototype.stop = function stop() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encrypt data with in-memory aes key.
|
||||
* @param {Buffer} data
|
||||
* @param {Buffer} iv
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
MasterKey.prototype.encipher = function encipher(data, iv) {
|
||||
if (!this.aesKey)
|
||||
return;
|
||||
@ -2056,6 +2141,13 @@ MasterKey.prototype.encipher = function encipher(data, iv) {
|
||||
return crypto.encipher(data, this.aesKey, iv.slice(0, 16));
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypt data with in-memory aes key.
|
||||
* @param {Buffer} data
|
||||
* @param {Buffer} iv
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
MasterKey.prototype.decipher = function decipher(data, iv) {
|
||||
if (!this.aesKey)
|
||||
return;
|
||||
@ -2107,6 +2199,13 @@ MasterKey.prototype.decrypt = co(function* decrypt(passphrase) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Decrypt the key permanently without a lock.
|
||||
* @private
|
||||
* @param {Buffer|String} passphrase - Zero this yourself.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
MasterKey.prototype._decrypt = co(function* decrypt(passphrase) {
|
||||
var data;
|
||||
|
||||
@ -2143,6 +2242,13 @@ MasterKey.prototype.encrypt = co(function* encrypt(passphrase) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Encrypt the key permanently without a lock.
|
||||
* @private
|
||||
* @param {Buffer|String} passphrase - Zero this yourself.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
MasterKey.prototype._encrypt = co(function* encrypt(passphrase) {
|
||||
var data, iv;
|
||||
|
||||
|
||||
@ -471,6 +471,13 @@ WalletDB.prototype.get = co(function* get(wid) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a wallet from the database without a lock.
|
||||
* @private
|
||||
* @param {WalletID} wid
|
||||
* @param {Function} callback - Returns [Error, {@link Wallet}].
|
||||
*/
|
||||
|
||||
WalletDB.prototype._get = co(function* get(wid) {
|
||||
var data = yield this.db.get(layout.w(wid));
|
||||
var wallet;
|
||||
@ -490,7 +497,6 @@ WalletDB.prototype._get = co(function* get(wid) {
|
||||
/**
|
||||
* Save a wallet to the database.
|
||||
* @param {Wallet} wallet
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
WalletDB.prototype.save = function save(wallet) {
|
||||
@ -548,6 +554,13 @@ WalletDB.prototype.create = co(function* create(options) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new wallet, save to database without a lock.
|
||||
* @private
|
||||
* @param {Object} options - See {@link Wallet}.
|
||||
* @param {Function} callback - Returns [Error, {@link Wallet}].
|
||||
*/
|
||||
|
||||
WalletDB.prototype._create = co(function* create(options) {
|
||||
var exists = yield this.has(options.id);
|
||||
var wallet;
|
||||
@ -611,11 +624,12 @@ WalletDB.prototype.getAccount = co(function* getAccount(wid, name) {
|
||||
return;
|
||||
|
||||
yield account.open();
|
||||
|
||||
return account;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get an account from the database. Do not setup watcher.
|
||||
* Get an account from the database by wid.
|
||||
* @private
|
||||
* @param {WalletID} wid
|
||||
* @param {Number} index - Account index.
|
||||
@ -942,6 +956,7 @@ WalletDB.prototype.getWallets = function getWallets() {
|
||||
/**
|
||||
* Rescan the blockchain.
|
||||
* @param {ChainDB} chaindb
|
||||
* @param {Number} height
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
@ -954,6 +969,14 @@ WalletDB.prototype.rescan = co(function* rescan(chaindb, height) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Rescan the blockchain without a lock.
|
||||
* @private
|
||||
* @param {ChainDB} chaindb
|
||||
* @param {Number} height
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
WalletDB.prototype._rescan = co(function* rescan(chaindb, height) {
|
||||
var self = this;
|
||||
var hashes;
|
||||
@ -1241,6 +1264,13 @@ WalletDB.prototype.addBlock = co(function* addBlock(entry, txs) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a block's transactions without a lock.
|
||||
* @private
|
||||
* @param {ChainEntry} entry
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
WalletDB.prototype._addBlock = co(function* addBlock(entry, txs) {
|
||||
var i, block, matches, hash, tx, wallets;
|
||||
|
||||
@ -1299,6 +1329,13 @@ WalletDB.prototype.removeBlock = co(function* removeBlock(entry) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unconfirm a block's transactions.
|
||||
* @private
|
||||
* @param {ChainEntry} entry
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
WalletDB.prototype._removeBlock = co(function* removeBlock(entry) {
|
||||
var block = WalletBlock.fromEntry(entry);
|
||||
var i, j, data, hash, wallets, wid, wallet;
|
||||
@ -1361,6 +1398,13 @@ WalletDB.prototype.addTX = co(function* addTX(tx, force) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a transaction to the database without a lock.
|
||||
* @private
|
||||
* @param {TX} tx
|
||||
* @param {Function} callback - Returns [Error].
|
||||
*/
|
||||
|
||||
WalletDB.prototype._addTX = co(function* addTX(tx, force) {
|
||||
var i, wallets, info, wallet;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user