wip
This commit is contained in:
parent
71ca53f8ba
commit
f83b8a63e3
@ -13,6 +13,7 @@ function Logger(options) {
|
|||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
this.formatting = _.isUndefined(options.formatting) ? Logger.DEFAULT_FORMATTING : options.formatting;
|
this.formatting = _.isUndefined(options.formatting) ? Logger.DEFAULT_FORMATTING : options.formatting;
|
||||||
|
this.permitWrites = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.DEFAULT_FORMATTING = true;
|
Logger.DEFAULT_FORMATTING = true;
|
||||||
@ -54,6 +55,9 @@ Logger.prototype.warn = function() {
|
|||||||
* #_log
|
* #_log
|
||||||
*/
|
*/
|
||||||
Logger.prototype._log = function(color) {
|
Logger.prototype._log = function(color) {
|
||||||
|
if (!this.permitWrites) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
args = args.slice(1);
|
args = args.slice(1);
|
||||||
var level = args.shift();
|
var level = args.shift();
|
||||||
|
|||||||
@ -123,21 +123,21 @@ Bitcoin.prototype._initDefaults = function(options) {
|
|||||||
|
|
||||||
Bitcoin.prototype._initCaches = function() {
|
Bitcoin.prototype._initCaches = function() {
|
||||||
// caches valid until there is a new block
|
// caches valid until there is a new block
|
||||||
this.utxosCache = LRU(50000);
|
this.utxosCache = LRU(500);
|
||||||
this.txidsCache = LRU(50000);
|
this.txidsCache = LRU(500);
|
||||||
this.balanceCache = LRU(50000);
|
this.balanceCache = LRU(500);
|
||||||
this.summaryCache = LRU(50000);
|
this.summaryCache = LRU(500);
|
||||||
this.blockOverviewCache = LRU(144);
|
this.blockOverviewCache = LRU(12);
|
||||||
this.transactionDetailedCache = LRU(100000);
|
this.transactionDetailedCache = LRU(1000);
|
||||||
|
|
||||||
// caches valid indefinitely
|
// caches valid indefinitely
|
||||||
this.transactionCache = LRU(100000);
|
this.transactionCache = LRU(1000);
|
||||||
this.rawTransactionCache = LRU(50000);
|
this.rawTransactionCache = LRU(500);
|
||||||
this.blockCache = LRU(144);
|
this.blockCache = LRU(12);
|
||||||
this.rawBlockCache = LRU(72);
|
this.rawBlockCache = LRU(6);
|
||||||
this.blockHeaderCache = LRU(288);
|
this.blockHeaderCache = LRU(24);
|
||||||
this.zmqKnownTransactions = LRU(5000);
|
this.zmqKnownTransactions = LRU(50);
|
||||||
this.zmqKnownBlocks = LRU(50);
|
this.zmqKnownBlocks = LRU(1);
|
||||||
this.lastTip = 0;
|
this.lastTip = 0;
|
||||||
this.lastTipTimeout = false;
|
this.lastTipTimeout = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -203,6 +203,7 @@ DB.prototype.start = function(callback) {
|
|||||||
|
|
||||||
this.node.once('ready', function() {
|
this.node.once('ready', function() {
|
||||||
// start syncing
|
// start syncing
|
||||||
|
log.permitWrites = false;
|
||||||
self._sync.initialSync();
|
self._sync.initialSync();
|
||||||
|
|
||||||
// Notify that there is a new tip
|
// Notify that there is a new tip
|
||||||
|
|||||||
@ -7,6 +7,10 @@ var EventEmitter = require('events').EventEmitter;
|
|||||||
var async = require('async');
|
var async = require('async');
|
||||||
var bitcore = require('bitcore-lib');
|
var bitcore = require('bitcore-lib');
|
||||||
var BufferUtil = bitcore.util.buffer;
|
var BufferUtil = bitcore.util.buffer;
|
||||||
|
var ProgressBar = require('progress');
|
||||||
|
var utils = require('../../utils.js');
|
||||||
|
var green = '\u001b[42m \u001b[0m';
|
||||||
|
var red = '\u001b[41m \u001b[0m';
|
||||||
|
|
||||||
function BlockStream(highWaterMark, bitcoind, lastHeight) {
|
function BlockStream(highWaterMark, bitcoind, lastHeight) {
|
||||||
Readable.call(this, {objectMode: true, highWaterMark: highWaterMark});
|
Readable.call(this, {objectMode: true, highWaterMark: highWaterMark});
|
||||||
@ -15,6 +19,7 @@ function BlockStream(highWaterMark, bitcoind, lastHeight) {
|
|||||||
this.stopping = false;
|
this.stopping = false;
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
this.processing = false;
|
this.processing = false;
|
||||||
|
this.latestHeightRetrieved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(BlockStream, Readable);
|
inherits(BlockStream, Readable);
|
||||||
@ -29,10 +34,12 @@ function ProcessConcurrent(highWaterMark, db) {
|
|||||||
|
|
||||||
inherits(ProcessConcurrent, Transform);
|
inherits(ProcessConcurrent, Transform);
|
||||||
|
|
||||||
function ProcessSerial(highWaterMark, db, tip) {
|
function ProcessSerial(highWaterMark, db, tip, progressBar) {
|
||||||
Writable.call(this, {objectMode: true, highWaterMark: highWaterMark});
|
Writable.call(this, {objectMode: true, highWaterMark: highWaterMark});
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.tip = tip;
|
this.tip = tip;
|
||||||
|
this.progressBar = progressBar;
|
||||||
|
this.processBlockStartTime = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(ProcessSerial, Writable);
|
inherits(ProcessSerial, Writable);
|
||||||
@ -58,6 +65,7 @@ function Sync(node, db) {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
this.syncing = false;
|
this.syncing = false;
|
||||||
this.highWaterMark = 100;
|
this.highWaterMark = 100;
|
||||||
|
this.progressBar = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(Sync, EventEmitter);
|
inherits(Sync, EventEmitter);
|
||||||
@ -70,27 +78,38 @@ Sync.prototype.initialSync = function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.syncing = true;
|
self.progressBar = new ProgressBar('[:bar] :percent :current blocks/sec: :blockspersec', {
|
||||||
this.blockStream = new BlockStream(this.highWaterMark, this.node.services.bitcoind, this.db.tip.__height);
|
complete: green,
|
||||||
var processConcurrent = new ProcessConcurrent(this.highWaterMark, this.db);
|
incomplete: red,
|
||||||
var writeStream = new WriteStream(this.highWaterMark, this.db);
|
total: self.node.services.bitcoind.height
|
||||||
var processSerial = new ProcessSerial(this.highWaterMark, this.db, this.db.tip);
|
});
|
||||||
|
|
||||||
this._handleErrors(this.blockStream);
|
console.log('tip: ', self.db.tip.__height);
|
||||||
this._handleErrors(processConcurrent);
|
self.progressBar.tick(self.db.tip.__height, {
|
||||||
this._handleErrors(processSerial);
|
blockspersec: 0.0000
|
||||||
this._handleErrors(writeStream);
|
});
|
||||||
|
self.syncing = true;
|
||||||
|
|
||||||
|
self.blockStream = new BlockStream(self.highWaterMark, self.node.services.bitcoind, self.db.tip.__height);
|
||||||
|
var processConcurrent = new ProcessConcurrent(self.highWaterMark, self.db);
|
||||||
|
var writeStream = new WriteStream(self.highWaterMark, self.db);
|
||||||
|
var processSerial = new ProcessSerial(self.highWaterMark, self.db, self.db.tip, self.progressBar);
|
||||||
|
|
||||||
|
self._handleErrors(self.blockStream);
|
||||||
|
self._handleErrors(processConcurrent);
|
||||||
|
self._handleErrors(processSerial);
|
||||||
|
self._handleErrors(writeStream);
|
||||||
|
|
||||||
processSerial.on('finish', function() {
|
processSerial.on('finish', function() {
|
||||||
self.syncing = false;
|
self.syncing = false;
|
||||||
self.emit('synced');
|
self.emit('synced');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.blockStream
|
self.blockStream
|
||||||
.pipe(processConcurrent)
|
.pipe(processConcurrent)
|
||||||
.pipe(writeStream);
|
.pipe(writeStream);
|
||||||
|
|
||||||
this.blockStream
|
self.blockStream
|
||||||
.pipe(processSerial);
|
.pipe(processSerial);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,67 +164,9 @@ Sync.prototype._handleErrors = function(stream) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// BlockStream.prototype._read = function() {
|
|
||||||
// var self = this;
|
|
||||||
|
|
||||||
// // TODO does not work :(
|
|
||||||
|
|
||||||
// var blockCount = Math.min(self.bitcoind.height - self.lastHeight, 5);
|
|
||||||
|
|
||||||
// if(blockCount <= 0 || this.stopping) {
|
|
||||||
// return self.push(null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// console.log('Fetching blocks ' + (self.lastHeight + 1) + ' to ' + (self.lastHeight + blockCount));
|
|
||||||
|
|
||||||
// async.times(blockCount, function(n, next) {
|
|
||||||
// var height = self.lastHeight + n + 1;
|
|
||||||
// self.bitcoind.getBlock(height, function(err, block) {
|
|
||||||
// if(err) {
|
|
||||||
// return next(err);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// block.__height = height;
|
|
||||||
|
|
||||||
// next(null, block);
|
|
||||||
// });
|
|
||||||
// }, function(err, blocks) {
|
|
||||||
// if(err) {
|
|
||||||
// return self.emit('error', err);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for(var i = 0; i < blocks.length; i++) {
|
|
||||||
// self.push(blocks[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// self.lastHeight += blocks.length;
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// BlockStream.prototype._read = function() {
|
|
||||||
// var self = this;
|
|
||||||
|
|
||||||
// self.lastHeight++;
|
|
||||||
// //console.log('Fetching block ' + self.lastHeight);
|
|
||||||
|
|
||||||
// var height = self.lastHeight;
|
|
||||||
|
|
||||||
// self.bitcoind.getBlock(height, function(err, block) {
|
|
||||||
// if(err) {
|
|
||||||
// return self.emit(err);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// block.__height = height;
|
|
||||||
|
|
||||||
// //console.log('pushing block ' + block.__height);
|
|
||||||
// self.push(block);
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
BlockStream.prototype._read = function() {
|
BlockStream.prototype._read = function() {
|
||||||
this.lastHeight++;
|
this.lastHeight++;
|
||||||
this.queue.push(this.lastHeight);
|
this.queue.push(this.lastHeight);
|
||||||
|
|
||||||
this._process();
|
this._process();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -226,15 +187,11 @@ BlockStream.prototype._process = function() {
|
|||||||
}, function(next) {
|
}, function(next) {
|
||||||
var heights = self.queue.slice(0, Math.min(5, self.queue.length));
|
var heights = self.queue.slice(0, Math.min(5, self.queue.length));
|
||||||
self.queue = self.queue.slice(heights.length);
|
self.queue = self.queue.slice(heights.length);
|
||||||
|
|
||||||
//console.log('fetching blocks ' + heights[0] + ' to ' + heights[heights.length - 1]);
|
|
||||||
|
|
||||||
async.map(heights, function(height, next) {
|
async.map(heights, function(height, next) {
|
||||||
self.bitcoind.getBlock(height, function(err, block) {
|
self.bitcoind.getBlock(height, function(err, block) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
block.__height = height;
|
block.__height = height;
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
@ -258,7 +215,6 @@ BlockStream.prototype._process = function() {
|
|||||||
if(err) {
|
if(err) {
|
||||||
return self.emit('error', err);
|
return self.emit('error', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.processing = false;
|
self.processing = false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -267,11 +223,11 @@ BlockStream.prototype._process = function() {
|
|||||||
|
|
||||||
ProcessSerial.prototype._write = function(block, enc, callback) {
|
ProcessSerial.prototype._write = function(block, enc, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.processBlockStartTime = process.hrtime();
|
||||||
|
|
||||||
function check() {
|
function check() {
|
||||||
return self.db.concurrentTip.__height >= block.__height;
|
return self.db.concurrentTip.__height >= block.__height;
|
||||||
}
|
}
|
||||||
//console.log('serial', block.__height);
|
|
||||||
|
|
||||||
var prevHash = BufferUtil.reverse(block.header.prevHash).toString('hex');
|
var prevHash = BufferUtil.reverse(block.header.prevHash).toString('hex');
|
||||||
if(prevHash !== self.tip.hash) {
|
if(prevHash !== self.tip.hash) {
|
||||||
@ -318,9 +274,10 @@ ProcessSerial.prototype._process = function(block, callback) {
|
|||||||
|
|
||||||
self.db.tip = block;
|
self.db.tip = block;
|
||||||
self.db.emit('addblock');
|
self.db.emit('addblock');
|
||||||
if(self.db.tip.__height % 100 === 0) {
|
|
||||||
console.log('Tip:', self.db.tip.__height);
|
self.progressBar.tick(1, {
|
||||||
}
|
blockspersec: (1 / utils.diffTime(self.processBlockStartTime)).toFixed(4)
|
||||||
|
});
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
@ -383,11 +340,9 @@ WriteStream.prototype._write = function(obj, enc, callback) {
|
|||||||
|
|
||||||
self.db.concurrentTip = obj.concurrentTip;
|
self.db.concurrentTip = obj.concurrentTip;
|
||||||
self.db.emit('concurrentaddblock');
|
self.db.emit('concurrentaddblock');
|
||||||
if(self.db.concurrentTip.__height - self.lastConcurrentOutputHeight >= 100) {
|
//if(self.db.concurrentTip.__height - self.lastConcurrentOutputHeight >= 100) {
|
||||||
console.log('Concurrent tip:', self.db.concurrentTip.__height);
|
|
||||||
self.lastConcurrentOutputHeight = self.db.concurrentTip.__height;
|
self.lastConcurrentOutputHeight = self.db.concurrentTip.__height;
|
||||||
}
|
//}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,7 +28,7 @@ Encoding.prototype.encodeTransactionValue = function(transaction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var inputValuesLengthBuffer = new Buffer(2);
|
var inputValuesLengthBuffer = new Buffer(2);
|
||||||
inputValuesLengthBuffer.writeUInt16BE(inputValues.length * 8);
|
inputValuesLengthBuffer.writeUInt16BE(inputValues.length);
|
||||||
|
|
||||||
return new Buffer.concat([heightBuffer, timestampBuffer,
|
return new Buffer.concat([heightBuffer, timestampBuffer,
|
||||||
inputValuesLengthBuffer, inputValuesBuffer, transaction.toBuffer()]);
|
inputValuesLengthBuffer, inputValuesBuffer, transaction.toBuffer()]);
|
||||||
|
|||||||
@ -142,7 +142,7 @@ TransactionService.prototype._getInputValues = function(tx, callback) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
if (!prevTx.outputs[input.outputIndex]) {
|
if (!prevTx.outputs[input.outputIndex]) {
|
||||||
return next(new Error('Input did not have utxo.'));
|
return next(new Error('Input did not have utxo: ' + prevTx.id + ' for tx: ' + tx.id));
|
||||||
}
|
}
|
||||||
var satoshis = prevTx.outputs[input.outputIndex].satoshis;
|
var satoshis = prevTx.outputs[input.outputIndex].satoshis;
|
||||||
next(null, satoshis);
|
next(null, satoshis);
|
||||||
|
|||||||
@ -5,17 +5,32 @@ var BufferReader = bitcore.encoding.BufferReader;
|
|||||||
|
|
||||||
function Encoding(servicePrefix) {
|
function Encoding(servicePrefix) {
|
||||||
this.servicePrefix = servicePrefix;
|
this.servicePrefix = servicePrefix;
|
||||||
this._subKeyMap = {
|
this.subKeyMap = {
|
||||||
transaction: new Buffer('00', 'hex'),
|
transaction: {
|
||||||
addresses: new Buffer('01', 'hex'),
|
fn: this.encodeWalletTransactionKey,
|
||||||
utxo: new Buffer('02', 'hex'),
|
buffer: new Buffer('00', 'hex')
|
||||||
utxoSat: new Buffer('03', 'hex'),
|
},
|
||||||
balance: new Buffer('04', 'hex')
|
addresses: {
|
||||||
|
fn: this.encodeWalletAddressesKey,
|
||||||
|
buffer: new Buffer('01', 'hex')
|
||||||
|
},
|
||||||
|
utxo: {
|
||||||
|
fn: this.encodeWalletUtxoKey,
|
||||||
|
buffer: new Buffer('02', 'hex')
|
||||||
|
},
|
||||||
|
utxoSat: {
|
||||||
|
fn: this.encodeWalletUtxoSatoshisKey,
|
||||||
|
buffer: new Buffer('03', 'hex')
|
||||||
|
},
|
||||||
|
balance: {
|
||||||
|
fn: this.encodeWalletBalanceKey,
|
||||||
|
buffer: new Buffer('04', 'hex')
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) {
|
Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) {
|
||||||
var buffers = [this.servicePrefix, this._subKeyMap.transaction];
|
var buffers = [this.servicePrefix, this.subKeyMap.transaction.buffer];
|
||||||
|
|
||||||
var walletIdSizeBuffer = new Buffer(1);
|
var walletIdSizeBuffer = new Buffer(1);
|
||||||
walletIdSizeBuffer.writeUInt8(walletId.length);
|
walletIdSizeBuffer.writeUInt8(walletId.length);
|
||||||
@ -24,11 +39,9 @@ Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) {
|
|||||||
buffers.push(walletIdSizeBuffer);
|
buffers.push(walletIdSizeBuffer);
|
||||||
buffers.push(walletIdBuffer);
|
buffers.push(walletIdBuffer);
|
||||||
|
|
||||||
if(height !== undefined) {
|
var heightBuffer = new Buffer(4);
|
||||||
var heightBuffer = new Buffer(4);
|
heightBuffer.writeUInt32BE(height || 0);
|
||||||
heightBuffer.writeUInt32BE(height);
|
buffers.push(heightBuffer);
|
||||||
buffers.push(heightBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.concat(buffers);
|
return Buffer.concat(buffers);
|
||||||
};
|
};
|
||||||
@ -58,7 +71,7 @@ Encoding.prototype.decodeWalletTransactionValue = function(buffer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) {
|
Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) {
|
||||||
var buffers = [this.servicePrefix, this._subKeyMap.utxo];
|
var buffers = [this.servicePrefix, this.subKeyMap.utxo.buffer];
|
||||||
|
|
||||||
var walletIdSizeBuffer = new Buffer(1);
|
var walletIdSizeBuffer = new Buffer(1);
|
||||||
walletIdSizeBuffer.writeUInt8(walletId.length);
|
walletIdSizeBuffer.writeUInt8(walletId.length);
|
||||||
@ -67,16 +80,12 @@ Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) {
|
|||||||
buffers.push(walletIdSizeBuffer);
|
buffers.push(walletIdSizeBuffer);
|
||||||
buffers.push(walletIdBuffer);
|
buffers.push(walletIdBuffer);
|
||||||
|
|
||||||
if(txid) {
|
var txidBuffer = new Buffer(txid || new Array(33).join('0'), 'hex');
|
||||||
var txidBuffer = new Buffer(txid, 'hex');
|
buffers.push(txidBuffer);
|
||||||
buffers.push(txidBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(outputIndex !== undefined) {
|
var outputIndexBuffer = new Buffer(4);
|
||||||
var outputIndexBuffer = new Buffer(4);
|
outputIndexBuffer.writeUInt32BE(outputIndex || 0);
|
||||||
outputIndexBuffer.writeUInt32BE(outputIndex);
|
buffers.push(outputIndexBuffer);
|
||||||
buffers.push(outputIndexBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.concat(buffers);
|
return Buffer.concat(buffers);
|
||||||
};
|
};
|
||||||
@ -117,7 +126,7 @@ Encoding.prototype.decodeWalletUtxoValue = function(buffer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, txid, outputIndex) {
|
Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, txid, outputIndex) {
|
||||||
var buffers = [this.servicePrefix, this._subKeyMap.utxoSat];
|
var buffers = [this.servicePrefix, this.subKeyMap.utxoSat.buffer];
|
||||||
|
|
||||||
var walletIdSizeBuffer = new Buffer(1);
|
var walletIdSizeBuffer = new Buffer(1);
|
||||||
walletIdSizeBuffer.writeUInt8(walletId.length);
|
walletIdSizeBuffer.writeUInt8(walletId.length);
|
||||||
@ -126,22 +135,16 @@ Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, tx
|
|||||||
buffers.push(walletIdSizeBuffer);
|
buffers.push(walletIdSizeBuffer);
|
||||||
buffers.push(walletIdBuffer);
|
buffers.push(walletIdBuffer);
|
||||||
|
|
||||||
if(satoshis !== undefined) {
|
var satoshisBuffer = new Buffer(8);
|
||||||
var satoshisBuffer = new Buffer(8);
|
satoshisBuffer.writeUInt32BE(satoshis || 0);
|
||||||
satoshisBuffer.writeUInt32BE(satoshis);
|
buffers.push(satoshisBuffer);
|
||||||
buffers.push(satoshisBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(txid) {
|
var txidBuffer = new Buffer(txid || new Array(33).join('0'), 'hex');
|
||||||
var txidBuffer = new Buffer(txid, 'hex');
|
buffers.push(txidBuffer);
|
||||||
buffers.push(txidBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(outputIndex !== undefined) {
|
var outputIndexBuffer = new Buffer(4);
|
||||||
var outputIndexBuffer = new Buffer(4);
|
outputIndexBuffer.writeUInt32BE(outputIndex || 0);
|
||||||
outputIndexBuffer.writeUInt32BE(outputIndex);
|
buffers.push(outputIndexBuffer);
|
||||||
buffers.push(outputIndexBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.concat(buffers);
|
return Buffer.concat(buffers);
|
||||||
};
|
};
|
||||||
@ -180,7 +183,7 @@ Encoding.prototype.decodeWalletUtxoSatoshisValue = function(buffer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletAddressesKey = function(walletId) {
|
Encoding.prototype.encodeWalletAddressesKey = function(walletId) {
|
||||||
var prefix = this._subKeyMap.addresses;
|
var prefix = this.subKeyMap.addresses.buffer;
|
||||||
var walletIdSizeBuffer = new Buffer(1);
|
var walletIdSizeBuffer = new Buffer(1);
|
||||||
walletIdSizeBuffer.writeUInt8(walletId.length);
|
walletIdSizeBuffer.writeUInt8(walletId.length);
|
||||||
var walletIdBuffer = new Buffer(walletId, 'utf8');
|
var walletIdBuffer = new Buffer(walletId, 'utf8');
|
||||||
@ -188,7 +191,10 @@ Encoding.prototype.encodeWalletAddressesKey = function(walletId) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.decodeWalletAddressesKey = function(buffer) {
|
Encoding.prototype.decodeWalletAddressesKey = function(buffer) {
|
||||||
return buffer.slice(3).toString('hex');
|
var reader = new BufferReader(buffer);
|
||||||
|
reader.read(3);
|
||||||
|
var walletSize = reader.readUInt8();
|
||||||
|
return reader.read(walletSize).toString('utf8');
|
||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletAddressesValue = function(addresses) {
|
Encoding.prototype.encodeWalletAddressesValue = function(addresses) {
|
||||||
@ -218,7 +224,7 @@ Encoding.prototype.decodeWalletAddressesValue = function(buffer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletBalanceKey = function(walletId) {
|
Encoding.prototype.encodeWalletBalanceKey = function(walletId) {
|
||||||
var prefix = this._subKeyMap.balance;
|
var prefix = this.subKeyMap.balance.buffer;
|
||||||
var walletIdSizeBuffer = new Buffer(1);
|
var walletIdSizeBuffer = new Buffer(1);
|
||||||
walletIdSizeBuffer.writeUInt8(walletId.length);
|
walletIdSizeBuffer.writeUInt8(walletId.length);
|
||||||
var walletIdBuffer = new Buffer(walletId, 'utf8');
|
var walletIdBuffer = new Buffer(walletId, 'utf8');
|
||||||
@ -226,7 +232,10 @@ Encoding.prototype.encodeWalletBalanceKey = function(walletId) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.decodeWalletBalanceKey = function(buffer) {
|
Encoding.prototype.decodeWalletBalanceKey = function(buffer) {
|
||||||
return buffer.slice(3).toString('hex');
|
var reader = new BufferReader(buffer);
|
||||||
|
reader.read(3);
|
||||||
|
var walletSize = reader.readUInt8();
|
||||||
|
return reader.read(walletSize).toString('utf8');
|
||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.encodeWalletBalanceValue = function(balance) {
|
Encoding.prototype.encodeWalletBalanceValue = function(balance) {
|
||||||
@ -236,8 +245,7 @@ Encoding.prototype.encodeWalletBalanceValue = function(balance) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Encoding.prototype.decodeWalletBalanceValue = function(buffer) {
|
Encoding.prototype.decodeWalletBalanceValue = function(buffer) {
|
||||||
var balance = buffer.readDoubleBE();
|
return buffer.readDoubleBE();
|
||||||
return balance;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Encoding;
|
module.exports = Encoding;
|
||||||
|
|||||||
@ -436,13 +436,13 @@ WalletService.prototype._endpointRemoveWallet = function() {
|
|||||||
return function(req, res) {
|
return function(req, res) {
|
||||||
var walletId = req.params.walletId;
|
var walletId = req.params.walletId;
|
||||||
|
|
||||||
self._removeWallet(walletId, function(err) {
|
self._removeWallet(walletId, function(err, numRecords) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return utils.sendError(err, res);
|
return utils.sendError(err, res);
|
||||||
}
|
}
|
||||||
res.status(200).jsonp({
|
res.status(200).jsonp({
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
result: 'removed'
|
numberRemoved: numRecords
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -469,6 +469,71 @@ WalletService.prototype._endpointGetAddresses = function() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
WalletService.prototype._endpointDumpAllWallets = function() {
|
||||||
|
var self = this;
|
||||||
|
return function(req, res) {
|
||||||
|
var keys = [];
|
||||||
|
|
||||||
|
var start = new Buffer(self.servicePrefix);
|
||||||
|
var end = new Buffer.concat([start, new Buffer('ff', 'hex')]);
|
||||||
|
|
||||||
|
var stream = self.store.createKeyStream({
|
||||||
|
gte: start,
|
||||||
|
lt: end
|
||||||
|
});
|
||||||
|
|
||||||
|
var streamErr = null;
|
||||||
|
stream.on('error', function(err) {
|
||||||
|
streamErr = err;
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('data', function(data) {
|
||||||
|
keys.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', function() {
|
||||||
|
if(streamErr) {
|
||||||
|
return utils.sendError(streamErr, res);
|
||||||
|
}
|
||||||
|
var resultsMap = keys.map(function(key) {
|
||||||
|
return key.toString('hex');
|
||||||
|
});
|
||||||
|
res.status(200).jsonp({
|
||||||
|
result: resultsMap
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WalletService.prototype._endpointGetWalletIds = function() {
|
||||||
|
var self = this;
|
||||||
|
return function(req, res) {
|
||||||
|
var start = new Buffer.concat([self.servicePrefix, new Buffer(self._encoding.subKeyMap.addresses.buffer)]);
|
||||||
|
var end = new Buffer.concat([start, new Buffer('ff', 'hex')]);
|
||||||
|
var stream = self.store.createKeyStream({
|
||||||
|
gte: start,
|
||||||
|
lt: end
|
||||||
|
});
|
||||||
|
var walletIds = [];
|
||||||
|
var streamErr;
|
||||||
|
stream.on('error', function(err) {
|
||||||
|
var streamErr = err;
|
||||||
|
});
|
||||||
|
stream.on('data', function(data) {
|
||||||
|
walletIds.push(self._encoding.decodeWalletAddressesKey(data));
|
||||||
|
});
|
||||||
|
stream.on('end', function() {
|
||||||
|
if(streamErr) {
|
||||||
|
return utils.sendError(streamErr, res);
|
||||||
|
}
|
||||||
|
res.status(200).jsonp({
|
||||||
|
walletIds: walletIds
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
WalletService.prototype._endpointPostAddresses = function() {
|
WalletService.prototype._endpointPostAddresses = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
return function(req, res) {
|
return function(req, res) {
|
||||||
@ -481,7 +546,7 @@ WalletService.prototype._endpointPostAddresses = function() {
|
|||||||
//if this is a post to /wallets, then it is expected that a new wallet is to be created
|
//if this is a post to /wallets, then it is expected that a new wallet is to be created
|
||||||
async.series([
|
async.series([
|
||||||
function(next) {
|
function(next) {
|
||||||
self._createWallet(walletId, [], function(err) {
|
self._createWallet(walletId, function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
@ -689,57 +754,53 @@ WalletService.prototype._getTransactions = function(walletId, options, callback)
|
|||||||
return callback(e);
|
return callback(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if (!self._cache.peek(key)) {
|
|
||||||
// self._getAddresses(walletId, function(err, addresses) {
|
|
||||||
// if(err) {
|
|
||||||
// return callback(err);
|
|
||||||
// }
|
|
||||||
// if (!addresses) {
|
|
||||||
// return callback(new Error('wallet not found'));
|
|
||||||
// }
|
|
||||||
// var addressGroups = self._chunkAdresses(addresses);
|
|
||||||
// async.eachSeries(addressGroups, function(addresses, next) {
|
|
||||||
// self.node.services.bitcoind.getAddressHistory(addresses, opts, function(err, history) {
|
|
||||||
// if(err) {
|
|
||||||
// return next(err);
|
|
||||||
// }
|
|
||||||
// var groupTransactions = history.items.map(function(item) {
|
|
||||||
// return item.tx;
|
|
||||||
// });
|
|
||||||
// transactions = _.union(transactions, groupTransactions);
|
|
||||||
// next();
|
|
||||||
// });
|
|
||||||
// }, function(err) {
|
|
||||||
// if(err) {
|
|
||||||
// return callback(err);
|
|
||||||
// }
|
|
||||||
// self._cache.set(key, JSON.stringify(transactions));
|
|
||||||
// finish();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
//} else {
|
|
||||||
// try {
|
|
||||||
// transactions = JSON.parse(self._cache.get(key));
|
|
||||||
// finish();
|
|
||||||
// } catch(e) {
|
|
||||||
// self._cache.del(key);
|
|
||||||
// return callback(e);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletService.prototype._removeWallet = function(walletId, callback) {
|
WalletService.prototype._removeWallet = function(walletId, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var boundary = self._encoding.encodeWalletAddressesKey(walletId);
|
async.map(Object.keys(self._encoding.subKeyMap), function(prefix, next) {
|
||||||
//wallet tz
|
var keys = [];
|
||||||
// wallet addresses
|
|
||||||
// utxo
|
|
||||||
// utxosat
|
|
||||||
//wallet balance
|
|
||||||
|
|
||||||
var txStream = self.store.createReadStream({
|
var walletIdBuffer = new Buffer(walletId, 'utf8');
|
||||||
gte: boundary
|
var start = self._encoding.subKeyMap[prefix].fn.call(self._encoding, walletId);
|
||||||
lte: boundary
|
var end = new Buffer.concat([self._encoding.subKeyMap[prefix].fn.call(self._encoding, walletId), new Buffer('ff', 'hex')]);
|
||||||
|
|
||||||
|
var stream = self.store.createKeyStream({
|
||||||
|
gte: start,
|
||||||
|
lt: end
|
||||||
|
});
|
||||||
|
|
||||||
|
var streamErr = null;
|
||||||
|
stream.on('error', function(err) {
|
||||||
|
streamErr = err;
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('data', function(data) {
|
||||||
|
keys.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', function() {
|
||||||
|
next(streamErr, keys);
|
||||||
|
});
|
||||||
|
|
||||||
|
}, function(err, results) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
results = _.flatten(results);
|
||||||
|
var operations = [];
|
||||||
|
for(var i = 0; i < results.length; i++) {
|
||||||
|
operations.push({
|
||||||
|
type: 'del',
|
||||||
|
key: results[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.store.batch(operations, function(err) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, operations.length);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -757,10 +818,10 @@ WalletService.prototype._getAddresses = function(walletId, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletService.prototype._createWallet = function(walletId, addresses, callback) {
|
WalletService.prototype._createWallet = function(walletId, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var key = self._encoding.encodeWalletAddressesKey(walletId);
|
var key = self._encoding.encodeWalletAddressesKey(walletId);
|
||||||
var value = self._encoding.encodeWalletAddressesValue(addresses);
|
var value = self._encoding.encodeWalletAddressesValue([]);
|
||||||
this.store.put(key, value, callback);
|
this.store.put(key, value, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -927,6 +988,9 @@ WalletService.prototype.setupRoutes = function(app) {
|
|||||||
app.get('/wallets/:walletId/balance',
|
app.get('/wallets/:walletId/balance',
|
||||||
s._endpointGetBalance()
|
s._endpointGetBalance()
|
||||||
);
|
);
|
||||||
|
app.get('/wallets/dump',
|
||||||
|
s._endpointDumpAllWallets()
|
||||||
|
);
|
||||||
app.get('/wallets/:walletId',
|
app.get('/wallets/:walletId',
|
||||||
s._endpointGetAddresses()
|
s._endpointGetAddresses()
|
||||||
);
|
);
|
||||||
@ -944,6 +1008,9 @@ WalletService.prototype.setupRoutes = function(app) {
|
|||||||
v.checkAddresses,
|
v.checkAddresses,
|
||||||
s._endpointPostAddresses()
|
s._endpointPostAddresses()
|
||||||
);
|
);
|
||||||
|
app.get('/wallets',
|
||||||
|
s._endpointGetWalletIds()
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletService.prototype.getRoutePrefix = function() {
|
WalletService.prototype.getRoutePrefix = function() {
|
||||||
|
|||||||
@ -97,4 +97,9 @@ utils.hasRequiredArgsForEncoding = function(args) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
utils.diffTime = function(time) {
|
||||||
|
var diff = process.hrtime(time);
|
||||||
|
return (diff[0] * 1E9 + diff[1])/(1E9 * 1.0);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = utils;
|
module.exports = utils;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user