From 1ccf4e9741527aef8331b4469eb443180a56aa28 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Wed, 1 Feb 2017 13:14:54 -0500 Subject: [PATCH] Added gettransactions. --- lib/services/wallet-api/index.js | 121 ++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 43 deletions(-) diff --git a/lib/services/wallet-api/index.js b/lib/services/wallet-api/index.js index 23071b23..636062d5 100644 --- a/lib/services/wallet-api/index.js +++ b/lib/services/wallet-api/index.js @@ -5,11 +5,6 @@ var BaseService = require('../../service'); var inherits = require('util').inherits; var index = require('../../'); var log = index.log; -var errors = index.errors; -var bitcore = require('bitcore-lib'); -var Networks = bitcore.Networks; -var levelup = require('levelup'); -var leveldown = require('leveldown'); var multer = require('multer'); var storage = multer.memoryStorage(); var upload = multer({ storage: storage }); @@ -20,13 +15,12 @@ var bodyParser = require('body-parser'); var LRU = require('lru-cache'); var Encoding = require('../../encoding'); // TODO this needs to be split out by service - var WalletService = function(options) { BaseService.call(this, options); this._cache = LRU({ max: 500 * 1024 * 1024, - length: function(n, key) { + length: function(n) { return Buffer.byteLength(n, 'utf8'); }, maxAge: 30 * 60 * 1000 @@ -210,7 +204,6 @@ WalletService.prototype.concurrentBlockHandler = function(block, connectBlock, c var self = this; var txs = block.transactions; - var height = block.__height; var action = 'put'; if (!connectBlock) { @@ -247,7 +240,7 @@ WalletService.prototype.concurrentBlockHandler = function(block, connectBlock, c type: action, key: self._encoding.encodeWalletTransactionKey(walletId, block.__height), value: self._encoding.encodeWalletTransactionValue(tx.id) - }) + }); }); } @@ -270,9 +263,9 @@ WalletService.prototype.concurrentBlockHandler = function(block, connectBlock, c continue; } - var walletIds = self._addressMap[inputAddress]; + var inputWalletIds = self._addressMap[inputAddress]; - walletIds.forEach(function(walletId) { + inputWalletIds.forEach(function(walletId) { operations.push({ type: action, key: self._encoding.encodeWalletTransactionKey(walletId, block.__height), @@ -433,8 +426,12 @@ WalletService.prototype._endpointPostAddresses = function() { var self = this; return function(req, res) { var addresses = req.addresses; + if (!addresses || !addresses.length) { + return utils.sendError(new Error('addresses are required when creating a wallet.')); + } var walletId = utils.getWalletId(); + // TODO make imdempotent self._importAddresses(walletId, addresses, function(err) { if(err) { return utils.sendError(err, res); @@ -492,6 +489,7 @@ WalletService.prototype._endpointPutAddresses = function() { var addAddresses = _.without(newAddresses, oldAddresses); var amountAdded = addAddresses.length; + //TODO this may take too long self._importAddresses(walletId, addAddresses, function(err) { if(err) { return utils.sendError(err, res); @@ -565,54 +563,90 @@ WalletService.prototype._chunkAdresses = function(addresses) { WalletService.prototype._getTransactions = function(walletId, options, callback) { var self = this; - var transactions = []; + var txids = []; var opts = { - start: options.start, - end: options.end + start: options.start || 0, + end: options.end || Math.pow(2, 32) - 1 }; var key = walletId + opts.start + opts.end; + function finish(transactions) { + var from = options.from || 0; + var to = options.to || transactions.length; + callback(null, transactions.slice(from, to), transactions.length); + } + 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) { + var stream = self.store.createReadStream({ + gte: self._encoding.encodeWalletTransactionKey(walletId, opts.start), + lt: self._encoding.encodeWalletTransactionKey(walletId, opts.end) + }); + + var streamErr; + stream.on('error', function(err) { + streamErr = err; + }); + + stream.on('data', function(data) { + txids.push(self._encoding.decodeWalletTransactionValue(data.value)); + }); + + stream.on('end', function() { + async.mapLimit(txids, function(txid, next) { + self.node.services.transaction.getTransaction(txid, options, next); + }, function(err, transactions) { if(err) { return callback(err); } self._cache.set(key, JSON.stringify(transactions)); - finish(); + finish(transactions); }); }); } else { try { transactions = JSON.parse(self._cache.get(key)); - finish(); + finish(transactions); } catch(e) { self._cache.del(key); return callback(e); } } - function finish() { - var from = options.from || 0; - var to = options.to || transactions.length; - callback(null, transactions.slice(from, to), transactions.length); - } + //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._getAddresses = function(walletId, callback) { @@ -738,7 +772,7 @@ WalletService.prototype._getTxidIndexOperations = function(walletId, addresses, return callback(err); } - operations = Object.keys(txids).map(function(txid) { + var operations = Object.keys(txids).map(function(txid) { return { type: 'put', key: self._encoding.encodeWalletTransactionKey(walletId, txids[txid]), @@ -767,7 +801,8 @@ WalletService.prototype._endpointGetInfo = function() { res.jsonp({result: 'ok'}); }; }; -WalletService.prototype.setupRoutes = function(app, express) { + +WalletService.prototype.setupRoutes = function(app) { var s = this; var v = validators;