diff --git a/lib/services/wallet-api/encoding.js b/lib/services/wallet-api/encoding.js index 2ca7da94..85b73965 100644 --- a/lib/services/wallet-api/encoding.js +++ b/lib/services/wallet-api/encoding.js @@ -5,10 +5,17 @@ var BufferReader = bitcore.encoding.BufferReader; function Encoding(servicePrefix) { this.servicePrefix = servicePrefix; + this._subKeyMap = { + transaction: new Buffer('00', 'hex'), + addresses: new Buffer('01', 'hex'), + utxo: new Buffer('02', 'hex'), + utxoSat: new Buffer('03', 'hex'), + balance: new Buffer('04', 'hex') + }; } Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) { - var buffers = [this.servicePrefix]; + var buffers = [this.servicePrefix, this._subKeyMap.transaction]; var walletIdSizeBuffer = new Buffer(1); walletIdSizeBuffer.writeUInt8(walletId.length); @@ -28,7 +35,7 @@ Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) { Encoding.prototype.decodeWalletTransactionKey = function(buffer) { var reader = new BufferReader(buffer); - reader.read(1); + reader.read(3); var walletSize = reader.readUInt8(); var walletId = reader.read(walletSize).toString('utf8'); @@ -51,7 +58,7 @@ Encoding.prototype.decodeWalletTransactionValue = function(buffer) { }; Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) { - var buffers = [this.servicePrefix]; + var buffers = [this.servicePrefix, this._subKeyMap.utxo]; var walletIdSizeBuffer = new Buffer(1); walletIdSizeBuffer.writeUInt8(walletId.length); @@ -76,7 +83,7 @@ Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) { Encoding.prototype.decodeWalletUtxoKey = function(buffer) { var reader = new BufferReader(buffer); - reader.read(1); + reader.read(3); var walletIdSize = reader.readUInt8(); var walletId = reader.read(walletIdSize).toString('utf8'); @@ -100,8 +107,8 @@ Encoding.prototype.encodeWalletUtxoValue = function(height, satoshis, scriptBuff Encoding.prototype.decodeWalletUtxoValue = function(buffer) { var reader = new BufferReader(buffer); var height = reader.readUInt32BE(); - var satoshis = reader.readDoubleBE(); - var scriptBuffer = reader.read(buffer.length - 12); + var satoshis = buffer.readDoubleBE(4); + var scriptBuffer = reader.read(12, buffer.length - 12); return { height: height, satoshis: satoshis, @@ -110,7 +117,7 @@ Encoding.prototype.decodeWalletUtxoValue = function(buffer) { }; Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, txid, outputIndex) { - var buffers = [this.servicePrefix]; + var buffers = [this.servicePrefix, this._subKeyMap.utxoSat]; var walletIdSizeBuffer = new Buffer(1); walletIdSizeBuffer.writeUInt8(walletId.length); @@ -141,12 +148,12 @@ Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, tx Encoding.prototype.decodeWalletUtxoSatoshisKey = function(buffer) { var reader = new BufferReader(buffer); - reader.read(1); + reader.read(3); - var walletIdSizeBuffer = reader.readUInt8(); - var walletId = reader.read(walletIdSizeBuffer).toString('utf8'); - var satoshis = reader.readDoubleBE(); - var txid = reader.read(32).toString('hex'); + var walletIdSize = reader.readUInt8(); + var walletId = reader.read(walletIdSize).toString('utf8'); + var satoshis = buffer.readDoubleBE(walletIdSize + 4); + var txid = reader.read(walletIdSize + 12, 32).toString('hex'); var outputIndex = reader.readUInt32BE(); return { walletId: walletId, @@ -173,9 +180,11 @@ Encoding.prototype.decodeWalletUtxoSatoshisValue = function(buffer) { }; Encoding.prototype.encodeWalletAddressesKey = function(walletId) { - var prefix = new Buffer('00', 'hex'); - var walletIdBuffer = new Buffer(walletId, 'hex'); - return Buffer.concat([this.servicePrefix, prefix, walletIdBuffer]); + var prefix = this._subKeyMap.addresses; + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + return Buffer.concat([this.servicePrefix, prefix, walletIdSizeBuffer, walletIdBuffer]); }; Encoding.prototype.decodeWalletAddressesKey = function(buffer) { @@ -201,19 +210,19 @@ Encoding.prototype.decodeWalletAddressesValue = function(buffer) { var reader = new BufferReader(buffer); var addressesLength = reader.readUInt32BE(); var addresses = []; - var addressSize = 0; - for(var i = 0; i < addressesLength.length; i++) { - addressSize = reader.readUInt8(addressSize); + for(var i = 0; i < addressesLength; i++) { + var addressSize = reader.readUInt8(); addresses.push(reader.read(addressSize).toString('utf8')); } - return addresses; }; Encoding.prototype.encodeWalletBalanceKey = function(walletId) { - var prefix = new Buffer('01', 'hex'); - var walletIdBuffer = new Buffer(walletId, 'hex'); - return Buffer.concat([this.servicePrefix, prefix, walletIdBuffer]); + var prefix = this._subKeyMap.balance; + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + return Buffer.concat([this.servicePrefix, prefix, walletIdSizeBuffer, walletIdBuffer]); }; Encoding.prototype.decodeWalletBalanceKey = function(buffer) { @@ -222,14 +231,12 @@ Encoding.prototype.decodeWalletBalanceKey = function(buffer) { Encoding.prototype.encodeWalletBalanceValue = function(balance) { var balanceBuffer = new Buffer(8); - balanceBuffer.writeUInt32BE(balance); + balanceBuffer.writeDoubleBE(balance); return balanceBuffer; }; Encoding.prototype.decodeWalletBalanceValue = function(buffer) { - var reader = new BufferReader(buffer); - var balance = reader.readDoubleBE(); - + var balance = buffer.readDoubleBE(); return balance; }; diff --git a/lib/services/wallet-api/index.js b/lib/services/wallet-api/index.js index 52338b98..a4f8d21f 100644 --- a/lib/services/wallet-api/index.js +++ b/lib/services/wallet-api/index.js @@ -34,7 +34,8 @@ inherits(WalletService, BaseService); WalletService.dependencies = [ 'bitcoind', - 'web' + 'web', + 'address' ]; WalletService.prototype.getAPIMethods = function() { @@ -327,8 +328,7 @@ WalletService.prototype._loadAllAddresses = function(callback) { stream.on('data', function(data) { var key = self._encoding.decodeWalletAddressesKey(data.key); var value = self._encoding.decodeWalletAddressesValue(data.value); - - value.addresses.forEach(function(address) { + value.forEach(function(address) { if(!self._addressMap[address]) { self._addressMap[address] = []; } @@ -392,7 +392,7 @@ WalletService.prototype._endpointUTXOs = function() { var options = { queryMempool: queryMempool }; - self._getUtxos(walletId, height, options, function(err, utxos) { + self._getUtxos(walletId, function(err, utxos) { if(err) { return utils.sendError(err, res); } @@ -422,7 +422,7 @@ WalletService.prototype._endpointGetBalance= function() { byAddress: byAddress }; - self._getBalance(walletId, height, options, function(err, result) { + self._getBalance(walletId, function(err, result) { if(err) { return utils.sendError(err, res); } @@ -431,6 +431,23 @@ WalletService.prototype._endpointGetBalance= function() { }; }; +WalletService.prototype._endpointRemoveWallet = function() { + var self = this; + return function(req, res) { + var walletId = req.params.walletId; + + self._removeWallet(walletId, function(err) { + if(err) { + return utils.sendError(err, res); + } + res.status(200).jsonp({ + walletId: walletId, + result: 'removed' + }); + }); + }; +}; + WalletService.prototype._endpointGetAddresses = function() { var self = this; return function(req, res) { @@ -461,15 +478,31 @@ WalletService.prototype._endpointPostAddresses = function() { } var walletId = utils.getWalletId(); - // TODO make imdempotent - self._importAddresses(walletId, addresses, function(err) { - if(err) { - return utils.sendError(err, res); - } - res.status(201).jsonp({ - walletId: walletId + //if this is a post to /wallets, then it is expected that a new wallet is to be created + async.series([ + function(next) { + self._createWallet(walletId, [], function(err) { + if(err) { + return next(err); + } + next(); + }); + }, function(next) { + // TODO make imdempotent + self._importAddresses(walletId, addresses, function(err) { + if(err) { + return next(err); + } + next(); + }); + }], function(err) { + if(err) { + return utils.sendError(err, res); + } + res.status(201).jsonp({ + walletId: walletId + }); }); - }); }; }; @@ -695,9 +728,24 @@ WalletService.prototype._getTransactions = function(walletId, options, callback) //} }; +WalletService.prototype._removeWallet = function(walletId, callback) { + var self = this; + var boundary = self._encoding.encodeWalletAddressesKey(walletId); + //wallet tz + // wallet addresses + // utxo + // utxosat + //wallet balance + + var txStream = self.store.createReadStream({ + gte: boundary + lte: boundary + }); +}; + WalletService.prototype._getAddresses = function(walletId, callback) { var self = this; - var key = self._encoding.encodeWalletAddressKey(walletId); + var key = self._encoding.encodeWalletAddressesKey(walletId); self.store.get(key, function(err, value) { if(err) { return callback(err); @@ -705,10 +753,17 @@ WalletService.prototype._getAddresses = function(walletId, callback) { if (!value) { return callback(null, []); } - callback(null, self._encoding.decodeWalletAddressValue(value)); + callback(null, self._encoding.decodeWalletAddressesValue(value)); }); }; +WalletService.prototype._createWallet = function(walletId, addresses, callback) { + var self = this; + var key = self._encoding.encodeWalletAddressesKey(walletId); + var value = self._encoding.encodeWalletAddressesValue(addresses); + this.store.put(key, value, callback); +}; + WalletService.prototype._importAddresses = function(walletId, addresses, callback) { var self = this; @@ -720,7 +775,7 @@ WalletService.prototype._importAddresses = function(walletId, addresses, callbac async.parallel( [ self._getUTXOIndexOperations.bind(self, walletId, addresses), - self._getTxidOperations.bind(self, walletId, addresses) + self._getTxidIndexOperations.bind(self, walletId, addresses) ], function(err, results) { if(err) { @@ -730,8 +785,8 @@ WalletService.prototype._importAddresses = function(walletId, addresses, callbac var operations = results[0].concat(results[1]); operations.push({ type: 'put', - key: self._encoding.encodeWalletAddressKey(walletId), - value: self._encoding.encodeWalletAddressValue(oldAddresses.concat(addresses)) + key: self._encoding.encodeWalletAddressesKey(walletId), + value: self._encoding.encodeWalletAddressesValue(oldAddresses.concat(addresses)) }); self.store.batch(operations, function(err) { @@ -772,7 +827,7 @@ WalletService.prototype._getUTXOIndexOperations = function(walletId, addresses, balance = initialBalance; } - self.services.address.getUnspentOutputs(addresses, function(err, utxos) { + self.node.services.address.getUnspentOutputs(addresses, false, function(err, utxos) { if(err) { return callback(err); } @@ -814,7 +869,7 @@ WalletService.prototype._getTxidIndexOperations = function(walletId, addresses, var txids = {}; async.eachLimit(addresses, 10, function(address, next) { - self.services.address.getAddressTxidsWithHeights(address, {}, function(err, tmpTxids) { + self.node.services.address.getAddressTxidsWithHeights(address, {}, function(err, tmpTxids) { if(err) { return next(err); } @@ -840,7 +895,7 @@ WalletService.prototype._getTxidIndexOperations = function(walletId, addresses, }; WalletService.prototype._storeAddresses = function(walletId, addresses, callback) { - var key = this._encoding.encodeWalletAddressKey(walletId); + var key = this._encoding.encodeWalletAddressesKey(walletId); var value = this._encoding.encodeWalletValue(addresses); this.store.put(key, value, callback); }; @@ -875,6 +930,9 @@ WalletService.prototype.setupRoutes = function(app) { app.get('/wallets/:walletId', s._endpointGetAddresses() ); + app.delete('/wallets/:walletId', + s._endpointRemoveWallet() + ); app.put('/wallets/:walletId/addresses', s._endpointPutAddresses() ); @@ -886,7 +944,6 @@ WalletService.prototype.setupRoutes = function(app) { v.checkAddresses, s._endpointPostAddresses() ); - }; WalletService.prototype.getRoutePrefix = function() {