diff --git a/lib/encoding.js b/lib/encoding.js index c57ab29e..b40476b8 100644 --- a/lib/encoding.js +++ b/lib/encoding.js @@ -7,193 +7,6 @@ function Encoding(servicePrefix) { this.servicePrefix = servicePrefix; } -Encoding.prototype.getTerminalKey = function(startKey) { - var endKey = Buffer.from(startKey); - endKey.writeUInt8(startKey.readUInt8(startKey.length - 1) + 1, startKey.length - 1); - return endKey; -}; - -Encoding.prototype.encodeAddressIndexKey = function(address, height, txid) { - var prefix = new Buffer('00', 'hex'); - var buffers = [this.servicePrefix, prefix]; - - var addressSizeBuffer = new Buffer(1); - addressSizeBuffer.writeUInt8(address.length); - var addressBuffer = new Buffer(address, 'utf8'); - - buffers.push(addressSizeBuffer); - buffers.push(addressBuffer); - - if(height !== undefined) { - var heightBuffer = new Buffer(4); - heightBuffer.writeUInt32BE(height); - buffers.push(heightBuffer); - } - - if(txid) { - var txidBuffer = new Buffer(txid, 'hex'); - buffers.push(txidBuffer); - } - - return Buffer.concat(buffers); -}; - -Encoding.prototype.decodeAddressIndexKey = function(buffer) { - var reader = new BufferReader(buffer); - reader.read(3); - - var addressSize = reader.readUInt8(); - var address = reader.read(addressSize).toString('utf8'); - var height = reader.readUInt32BE(); - var txid = reader.read(32).toString('hex'); - return { - address: address, - height: height, - txid: txid, - }; -}; - -Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) { - var prefix = new Buffer('01', 'hex'); - var buffers = [this.servicePrefix, prefix]; - - var addressSizeBuffer = new Buffer(1); - addressSizeBuffer.writeUInt8(address.length); - var addressBuffer = new Buffer(address, 'utf8'); - - buffers.push(addressSizeBuffer); - buffers.push(addressBuffer); - - if(txid) { - var txidBuffer = new Buffer(txid, 'hex'); - buffers.push(txidBuffer); - } - - if(outputIndex !== undefined) { - var outputIndexBuffer = new Buffer(4); - outputIndexBuffer.writeUInt32BE(outputIndex); - buffers.push(outputIndexBuffer); - } - - return Buffer.concat(buffers); -}; - -Encoding.prototype.decodeUtxoIndexKey = function(buffer) { - var reader = new BufferReader(buffer); - reader.read(3); - - var addressSize = reader.readUInt8(); - var address = reader.read(addressSize).toString('utf8'); - var txid = reader.read(32).toString('hex'); - var outputIndex = reader.readUInt32BE(4); - - return { - address: address, - txid: txid, - outputIndex: outputIndex - }; -}; - -Encoding.prototype.encodeUtxoIndexValue = function(height, satoshis, scriptBuffer) { - var heightBuffer = new Buffer(4); - heightBuffer.writeUInt32BE(height); - var satoshisBuffer = new Buffer(8); - satoshisBuffer.writeDoubleBE(satoshis); - return Buffer.concat([heightBuffer, satoshisBuffer, scriptBuffer]); -}; - -Encoding.prototype.decodeUtxoIndexValue = function(buffer) { - var reader = new BufferReader(buffer); - var height = reader.readUInt32BE(); - var satoshis = reader.readDoubleBE(); - var scriptBuffer = reader.read(buffer.length - 12); - return { - height: height, - satoshis: satoshis, - script: scriptBuffer - }; -}; - -Encoding.prototype.encodeTransactionKey = function(txid) { - return Buffer.concat([this.servicePrefix, new Buffer(txid, 'hex')]); -}; - -Encoding.prototype.decodeTransactionKey = function(buffer) { - return buffer.slice(2).toString('hex'); -}; - -Encoding.prototype.encodeTransactionValue = function(transaction) { - var heightBuffer = new Buffer(4); - heightBuffer.writeUInt32BE(transaction.__height); - - var timestampBuffer = new Buffer(8); - timestampBuffer.writeDoubleBE(transaction.__timestamp); - - var inputValues = transaction.__inputValues; - var inputValuesBuffer = new Buffer(8 * inputValues.length); - for(var i = 0; i < inputValues.length; i++) { - inputValuesBuffer.writeDoubleBE(inputValues[i], i * 8); - } - - var inputValuesLengthBuffer = new Buffer(2); - inputValuesLengthBuffer.writeUInt16BE(inputValues.length * 8); - - return new Buffer.concat([heightBuffer, timestampBuffer, - inputValuesLengthBuffer, inputValuesBuffer, transaction.toBuffer()]); -}; - -Encoding.prototype.decodeTransactionValue = function(buffer) { - var height = buffer.readUInt32BE(); - - var timestamp = buffer.readDoubleBE(4); - - var inputValues = []; - var inputValuesLength = buffer.readUInt16BE(12); - for(var i = 0; i < inputValuesLength / 8; i++) { - inputValues.push(buffer.readDoubleBE(i * 8 + 14)); - } - var transaction = new bitcore.Transaction(buffer.slice(inputValues.length * 8 + 14)); - transaction.__height = height; - transaction.__inputValues = inputValues; - transaction.__timestamp = timestamp; - return transaction; -}; - -Encoding.prototype.encodeBlockTimestampKey = function(hash) { - return Buffer.concat([this.servicePrefix, new Buffer(hash, 'hex')]); -}; - -Encoding.prototype.decodeBlockTimestampKey = function(buffer) { - return buffer.slice(2).toString('hex'); -}; - -Encoding.prototype.encodeBlockTimestampValue = function(timestamp) { - var timestampBuffer = new Buffer(new Array(8)); - timestampBuffer.writeDoubleBE(timestamp); - return timestampBuffer; -}; - -Encoding.prototype.decodeBlockTimestampValue = function(buffer) { - return buffer.readDoubleBE(0); -}; - -Encoding.prototype.encodeTimestampBlockKey = function(timestamp) { - var timestampBuffer = new Buffer(new Array(8)); - timestampBuffer.writeDoubleBE(timestamp); - return Buffer.concat([this.servicePrefix, timestampBuffer]); -}; - -Encoding.prototype.decodeTimestampBlockKey = function(buffer) { - return buffer.readDoubleBE(2); -}; - -Encoding.prototype.encodeTimestampBlockValue = function(hash) { - return new Buffer(hash, 'hex'); -}; - -Encoding.prototype.decodeTimestampBlockValue = function(buffer) { - return buffer.toString('hex'); -}; Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) { var buffers = [this.servicePrefix]; diff --git a/lib/services/address/encoding.js b/lib/services/address/encoding.js new file mode 100644 index 00000000..96a7b452 --- /dev/null +++ b/lib/services/address/encoding.js @@ -0,0 +1,118 @@ +'use strict'; + +var bitcore = require('bitcore-lib'); +var BufferReader = bitcore.encoding.BufferReader; + +function Encoding(servicePrefix) { + this.servicePrefix = servicePrefix; +} + +Encoding.prototype.getTerminalKey = function(startKey) { + var endKey = Buffer.from(startKey); + endKey.writeUInt8(startKey.readUInt8(startKey.length - 1) + 1, startKey.length - 1); + return endKey; +}; + +Encoding.prototype.encodeAddressIndexKey = function(address, height, txid) { + var prefix = new Buffer('00', 'hex'); + var buffers = [this.servicePrefix, prefix]; + + var addressSizeBuffer = new Buffer(1); + addressSizeBuffer.writeUInt8(address.length); + var addressBuffer = new Buffer(address, 'utf8'); + + buffers.push(addressSizeBuffer); + buffers.push(addressBuffer); + + if(height !== undefined) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + buffers.push(heightBuffer); + } + + if(txid) { + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeAddressIndexKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(3); + + var addressSize = reader.readUInt8(); + var address = reader.read(addressSize).toString('utf8'); + var height = reader.readUInt32BE(); + var txid = reader.read(32).toString('hex'); + return { + address: address, + height: height, + txid: txid, + }; +}; + +Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) { + var prefix = new Buffer('01', 'hex'); + var buffers = [this.servicePrefix, prefix]; + + var addressSizeBuffer = new Buffer(1); + addressSizeBuffer.writeUInt8(address.length); + var addressBuffer = new Buffer(address, 'utf8'); + + buffers.push(addressSizeBuffer); + buffers.push(addressBuffer); + + if(txid) { + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + } + + if(outputIndex !== undefined) { + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + buffers.push(outputIndexBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeUtxoIndexKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(3); + + var addressSize = reader.readUInt8(); + var address = reader.read(addressSize).toString('utf8'); + var txid = reader.read(32).toString('hex'); + var outputIndex = reader.readUInt32BE(4); + + return { + address: address, + txid: txid, + outputIndex: outputIndex + }; +}; + +Encoding.prototype.encodeUtxoIndexValue = function(height, satoshis, scriptBuffer) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + var satoshisBuffer = new Buffer(8); + satoshisBuffer.writeDoubleBE(satoshis); + return Buffer.concat([heightBuffer, satoshisBuffer, scriptBuffer]); +}; + +Encoding.prototype.decodeUtxoIndexValue = function(buffer) { + var reader = new BufferReader(buffer); + var height = reader.readUInt32BE(); + var satoshis = reader.readDoubleBE(); + var scriptBuffer = reader.read(buffer.length - 12); + return { + height: height, + satoshis: satoshis, + script: scriptBuffer + }; +}; + +module.exports = Encoding; + diff --git a/lib/services/address/index.js b/lib/services/address/index.js index d3abcf90..6a7c1f3e 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -1,26 +1,19 @@ 'use strict'; -var fs = require('fs'); var BaseService = require('../../service'); var inherits = require('util').inherits; var async = require('async'); -var mkdirp = require('mkdirp'); 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 memdown = require('memdown'); var $ = bitcore.util.preconditions; var _ = bitcore.deps._; -var Hash = bitcore.crypto.Hash; var EventEmitter = require('events').EventEmitter; var Address = bitcore.Address; -var AddressHistory = require('./history'); var constants = require('../../constants'); -var Encoding = require('../../encoding'); +var Encoding = require('./encoding'); var InputsTransformStream = require('./streams/inputs-transform'); var OutputsTransformStream = require('./streams/outputs-transform'); @@ -149,7 +142,6 @@ AddressService.prototype.concurrentBlockHandler = function(block, connectBlock, var operations = []; - var transactionLength = txs.length; for(var i = 0; i < txs.length; i++) { var tx = txs[i]; @@ -234,7 +226,6 @@ AddressService.prototype.blockHandler = function(block, connectBlock, callback) var self = this; var txs = block.transactions; - var height = block.__height; var action = 'put'; var reverseAction = 'del'; @@ -659,6 +650,7 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) { var hashTypeBuffer = addrObj.hashTypeBuffer; var stream = this.createInputsStream(addressStr, options); + var error; stream.on('data', function(input) { inputs.push(input); @@ -669,8 +661,6 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) { } }); - var error; - stream.on('error', function(streamError) { if (streamError) { error = streamError; @@ -880,6 +870,7 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) { var outputs = []; var stream = this.createOutputsStream(addressStr, options); + var error; stream.on('data', function(data) { outputs.push(data); @@ -890,8 +881,6 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) { } }); - var error; - stream.on('error', function(streamError) { if (streamError) { error = streamError; @@ -1137,7 +1126,7 @@ AddressService.prototype.getAddressHistory = function(addresses, options, callba txids = _.union(txids, tmpTxids); return next(); }); - }, function(err) { + }, function() { async.mapLimit(txids, self.concurrency, function(txid, next) { self.node.services.transaction.getTransaction(txid, options, function(err, tx) { if(err) { @@ -1331,6 +1320,7 @@ AddressService.prototype._getAddressConfirmedOutputsSummary = function(address, var count = 0; var outputStream = self.createOutputsStream(address, options); + var error = null; outputStream.on('data', function(output) { @@ -1372,7 +1362,6 @@ AddressService.prototype._getAddressConfirmedOutputsSummary = function(address, }); - var error = null; outputStream.on('error', function(err) { error = err; diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind/index.js similarity index 99% rename from lib/services/bitcoind.js rename to lib/services/bitcoind/index.js index 99ea7196..091d666e 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind/index.js @@ -14,11 +14,11 @@ var $ = bitcore.util.preconditions; var _ = bitcore.deps._; var Transaction = bitcore.Transaction; -var index = require('../'); +var index = require('../../'); var errors = index.errors; var log = index.log; -var utils = require('../utils'); -var Service = require('../service'); +var utils = require('../../utils'); +var Service = require('../../service'); /** * Provides a friendly event driven API to bitcoind in Node.js. Manages starting and diff --git a/lib/services/db/encoding.js b/lib/services/db/encoding.js new file mode 100644 index 00000000..e69de29b diff --git a/lib/services/mempool/encoding.js b/lib/services/mempool/encoding.js new file mode 100644 index 00000000..1b127516 --- /dev/null +++ b/lib/services/mempool/encoding.js @@ -0,0 +1,234 @@ +'use strict'; + +var bitcore = require('bitcore-lib'); +var BufferReader = bitcore.encoding.BufferReader; + +function Encoding(servicePrefix) { + this.servicePrefix = servicePrefix; +} + +Encoding.prototype.encodeMempoolAddressIndexKey = function(address, txid) { + var prefix = new Buffer('00', 'hex'); + var buffers = [this.servicePrefix, prefix]; + + var addressSizeBuffer = new Buffer(1); + addressSizeBuffer.writeUInt8(address.length); + buffers.push(addressSizeBuffer); + var addressBuffer = new Buffer(address, 'utf8'); + buffers.push(addressBuffer); + + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + + return Buffer.concat(buffers); +}; + +Encoding.prototype.encodeMempoolAddressIndexValue = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(1); + + var addressSize = reader.readUInt8(); + var address = reader.read(addressSize).toString('utf8'); + var txid = reader.read(32).toString('hex'); + + return { + address: address, + txid: txid + }; +}; + +Encoding.prototype.encodeMempoolAddressIndexValue = function(address, txid) { +}; +Encoding.prototype.encodeWalletTransactionValue = function(txid) { + return new Buffer(txid, 'hex'); +}; + +Encoding.prototype.decodeWalletTransactionValue = function(buffer) { + return buffer.toString('hex'); +}; + +Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) { + var buffers = [this.servicePrefix]; + + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + + buffers.push(walletIdSizeBuffer); + buffers.push(walletIdBuffer); + + if(txid) { + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + } + + if(outputIndex !== undefined) { + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + buffers.push(outputIndexBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeWalletUtxoKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(1); + + var walletIdSize = reader.readUInt8(); + var walletId = reader.read(walletIdSize).toString('utf8'); + var txid = reader.read(32).toString('hex'); + var outputIndex = reader.readUInt32BE(); + return { + walletId: walletId, + txid: txid, + outputIndex: outputIndex + }; +}; + +Encoding.prototype.encodeWalletUtxoValue = function(height, satoshis, scriptBuffer) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + var satoshisBuffer = new Buffer(8); + satoshisBuffer.writeDoubleBE(satoshis); + return Buffer.concat([height, satoshisBuffer, scriptBuffer]); +}; + +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); + return { + height: height, + satoshis: satoshis, + script: scriptBuffer + }; +}; + +Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, txid, outputIndex) { + var buffers = [this.servicePrefix]; + + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + + buffers.push(walletIdSizeBuffer); + buffers.push(walletIdBuffer); + + if(satoshis !== undefined) { + var satoshisBuffer = new Buffer(8); + satoshisBuffer.writeUInt32BE(satoshis); + buffers.push(satoshisBuffer); + } + + if(txid) { + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + } + + if(outputIndex !== undefined) { + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + buffers.push(outputIndexBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeWalletUtxoSatoshisKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(1); + + var walletIdSizeBuffer = reader.readUInt8(); + var walletId = reader.read(walletIdSizeBuffer).toString('utf8'); + var satoshis = reader.readDoubleBE(); + var txid = reader.read(32).toString('hex'); + var outputIndex = reader.readUInt32BE(); + return { + walletId: walletId, + satoshis: satoshis, + txid: txid, + outputIndex: outputIndex + }; +}; + +Encoding.prototype.encodeWalletUtxoSatoshisValue = function(height, scriptBuffer) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + return Buffer.concat([height, scriptBuffer]); +}; + +Encoding.prototype.decodeWalletUtxoSatoshisValue = function(buffer) { + var reader = new BufferReader(buffer); + var height = reader.readUInt32BE(); + var scriptBuffer = reader.read(buffer.length - 4); + return { + height: height, + script: scriptBuffer + }; +}; + +Encoding.prototype.encodeWalletAddressesKey = function(walletId) { + var prefix = new Buffer('00', 'hex'); + var walletIdBuffer = new Buffer(walletId, 'hex'); + return Buffer.concat([this.servicePrefix, prefix, walletIdBuffer]); +}; + +Encoding.prototype.decodeWalletAddressesKey = function(buffer) { + return buffer.slice(3).toString('hex'); +}; + +Encoding.prototype.encodeWalletAddressesValue = function(addresses) { + var bufferList = []; + var addressesLengthBuffer = new Buffer(4); + addressesLengthBuffer.writeUInt32BE(addresses.length); + bufferList.push(addressesLengthBuffer); + for(var i = 0; i < addresses.length; i++) { + var addressSizeBuffer = new Buffer(1); + addressSizeBuffer.writeUInt8(addresses[i].length); + bufferList.push(addressSizeBuffer); + bufferList.push(new Buffer(addresses[i], 'utf8')); + } + + return Buffer.concat(bufferList); +}; + +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); + 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]); +}; + +Encoding.prototype.decodeWalletBalanceKey = function(buffer) { + return buffer.slice(3).toString('hex'); +}; + +Encoding.prototype.encodeWalletBalanceValue = function(balance) { + var balanceBuffer = new Buffer(8); + balanceBuffer.writeUInt32BE(balance); + return balanceBuffer; +}; + +Encoding.prototype.decodeWalletBalanceValue = function(buffer) { + var reader = new BufferReader(buffer); + var balance = reader.readDoubleBE(); + + return balance; +}; + +module.exports = Encoding; + diff --git a/lib/services/mempool.js b/lib/services/mempool/index.js similarity index 96% rename from lib/services/mempool.js rename to lib/services/mempool/index.js index 04be9a50..41ff7d0b 100644 --- a/lib/services/mempool.js +++ b/lib/services/mempool/index.js @@ -1,15 +1,14 @@ 'use strict'; -var BaseService = require('../service'); +var BaseService = require('../../service'); var util = require('util'); -var EventEmitter = require('events').EventEmitter; var bitcore = require('bitcore-lib'); -var Encoding = require('../encoding'); -var index = require('../index'); +var Encoding = require('./encoding'); +var index = require('../../index'); var log = index.log; var async = require('async'); -var MempoolService = function(options) { - EventEmitter.call(this); +var MempoolService = function(options) { + BaseService.call(this, options); this.node = options.node; this.name = options.name; this._txIndex = {}; @@ -20,9 +19,6 @@ var MempoolService = function(options) { util.inherits(MempoolService, BaseService); -/** - * Describes the dependencies that should be loaded before this service. - */ MempoolService.dependencies = [ 'bitcoind', 'db' ]; MempoolService.prototype.blockHandler = function(block, connectBlock, callback) { @@ -133,7 +129,6 @@ MempoolService.prototype._getTransactionAddressDetailOperations = function(tx, a } - //TODO deal with P2PK for(var i = 0; i < inputs.length; i++) { var input = inputs[i]; diff --git a/lib/services/timestamp/encoding.js b/lib/services/timestamp/encoding.js new file mode 100644 index 00000000..d1ae6fb9 --- /dev/null +++ b/lib/services/timestamp/encoding.js @@ -0,0 +1,43 @@ +'use strict'; + +function Encoding(servicePrefix) { + this.servicePrefix = servicePrefix; +} + +Encoding.prototype.encodeBlockTimestampKey = function(hash) { + return Buffer.concat([this.servicePrefix, new Buffer(hash, 'hex')]); +}; + +Encoding.prototype.decodeBlockTimestampKey = function(buffer) { + return buffer.slice(2).toString('hex'); +}; + +Encoding.prototype.encodeBlockTimestampValue = function(timestamp) { + var timestampBuffer = new Buffer(new Array(8)); + timestampBuffer.writeDoubleBE(timestamp); + return timestampBuffer; +}; + +Encoding.prototype.decodeBlockTimestampValue = function(buffer) { + return buffer.readDoubleBE(0); +}; + +Encoding.prototype.encodeTimestampBlockKey = function(timestamp) { + var timestampBuffer = new Buffer(new Array(8)); + timestampBuffer.writeDoubleBE(timestamp); + return Buffer.concat([this.servicePrefix, timestampBuffer]); +}; + +Encoding.prototype.decodeTimestampBlockKey = function(buffer) { + return buffer.readDoubleBE(2); +}; + +Encoding.prototype.encodeTimestampBlockValue = function(hash) { + return new Buffer(hash, 'hex'); +}; + +Encoding.prototype.decodeTimestampBlockValue = function(buffer) { + return buffer.toString('hex'); +}; + +module.exports = Encoding; diff --git a/lib/services/timestamp.js b/lib/services/timestamp/index.js similarity index 95% rename from lib/services/timestamp.js rename to lib/services/timestamp/index.js index 45e848af..05430ffb 100644 --- a/lib/services/timestamp.js +++ b/lib/services/timestamp/index.js @@ -1,6 +1,6 @@ 'use strict'; -var Encoding = require('../encoding'); -var BaseService = require('../service'); +var Encoding = require('./encoding'); +var BaseService = require('../../service'); var inherits = require('util').inherits; function TimestampService(options) { @@ -11,9 +11,7 @@ function TimestampService(options) { inherits(TimestampService, BaseService); -TimestampService.dependencies = [ - 'db' -]; +TimestampService.dependencies = [ 'db' ]; TimestampService.prototype.start = function(callback) { var self = this; diff --git a/lib/services/transaction/encoding.js b/lib/services/transaction/encoding.js new file mode 100644 index 00000000..95e6dc59 --- /dev/null +++ b/lib/services/transaction/encoding.js @@ -0,0 +1,55 @@ +'use strict'; + +var bitcore = require('bitcore-lib'); + +function Encoding(servicePrefix) { + this.servicePrefix = servicePrefix; +} + +Encoding.prototype.encodeTransactionKey = function(txid) { + return Buffer.concat([this.servicePrefix, new Buffer(txid, 'hex')]); +}; + +Encoding.prototype.decodeTransactionKey = function(buffer) { + return buffer.slice(2).toString('hex'); +}; + +Encoding.prototype.encodeTransactionValue = function(transaction) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(transaction.__height); + + var timestampBuffer = new Buffer(8); + timestampBuffer.writeDoubleBE(transaction.__timestamp); + + var inputValues = transaction.__inputValues; + var inputValuesBuffer = new Buffer(8 * inputValues.length); + for(var i = 0; i < inputValues.length; i++) { + inputValuesBuffer.writeDoubleBE(inputValues[i], i * 8); + } + + var inputValuesLengthBuffer = new Buffer(2); + inputValuesLengthBuffer.writeUInt16BE(inputValues.length * 8); + + return new Buffer.concat([heightBuffer, timestampBuffer, + inputValuesLengthBuffer, inputValuesBuffer, transaction.toBuffer()]); +}; + +Encoding.prototype.decodeTransactionValue = function(buffer) { + var height = buffer.readUInt32BE(); + + var timestamp = buffer.readDoubleBE(4); + + var inputValues = []; + var inputValuesLength = buffer.readUInt16BE(12); + for(var i = 0; i < inputValuesLength / 8; i++) { + inputValues.push(buffer.readDoubleBE(i * 8 + 14)); + } + var transaction = new bitcore.Transaction(buffer.slice(inputValues.length * 8 + 14)); + transaction.__height = height; + transaction.__inputValues = inputValues; + transaction.__timestamp = timestamp; + return transaction; +}; + +module.exports = Encoding; + diff --git a/lib/services/transaction.js b/lib/services/transaction/index.js similarity index 94% rename from lib/services/transaction.js rename to lib/services/transaction/index.js index f730e93a..819ccf0a 100644 --- a/lib/services/transaction.js +++ b/lib/services/transaction/index.js @@ -1,14 +1,9 @@ 'use strict'; var async = require('async'); -var BaseService = require('../service'); +var BaseService = require('../../service'); var inherits = require('util').inherits; -var bitcore = require('bitcore-lib'); -var _ = require('lodash'); -var Encoding = require('../encoding'); -var LRU = require('lru-cache'); -var utils = require('./wallet-api/utils'); -var index = require('../'); +var Encoding = require('./encoding'); /** * The Transaction Service builds upon the Database Service and the Bitcoin Service to add additional @@ -173,9 +168,9 @@ TransactionService.prototype.getTransaction = function(txid, options, callback) return callback(err); } var tx = self.encoding.decodeTransactionValue(buffer); - callback(null, tx); + next(null, tx); }); - }, function(next, tx) { + }, function(tx, next) { if (tx) { return next(null, tx); } diff --git a/lib/services/untrusted-mempool/encoding.js b/lib/services/untrusted-mempool/encoding.js new file mode 100644 index 00000000..e69de29b diff --git a/lib/services/untrusted-mempool.js b/lib/services/untrusted-mempool/index.js similarity index 96% rename from lib/services/untrusted-mempool.js rename to lib/services/untrusted-mempool/index.js index ce37cbf1..ca82879b 100644 --- a/lib/services/untrusted-mempool.js +++ b/lib/services/untrusted-mempool/index.js @@ -19,7 +19,6 @@ */ var p2p = require('bitcore-p2p'); -var Peer = p2p.Peer; var messages = new p2p.Messages(); var LRU = require('lru-cache'); var util = require('util'); @@ -27,12 +26,13 @@ var _ = require('lodash'); var bitcore = require('bitcore-lib'); var index = require('../'); var log = index.log; -var Service = require('../service'); +var Service = require('../../service'); var UntrustedMempool = function(options) { if (!(this instanceof UntrustedMempool)) { return new UntrustedMempool(options); } + Service.call(this, options); this.options = options; this._maxPeers = this.options.maxPeers || 60; @@ -43,7 +43,7 @@ var UntrustedMempool = function(options) { util.inherits(UntrustedMempool, Service); -UntrustedMempool.dependencies = [ bitcoind, db ]; +UntrustedMempool.dependencies = [ 'bitcoind', 'db' ]; UntrustedMempool.prototype.start = function(callback) { var self = this; @@ -103,6 +103,10 @@ UntrustedMempool.prototype._initPool = function() { this._setupListeners(); }; +UntrustedMempool.prototype.validTx = function(tx) { + return tx; +}; + UntrustedMempool.prototype._setupListeners = function() { var self = this; @@ -129,7 +133,7 @@ UntrustedMempool.prototype._setupListeners = function() { self._pool.on('peertx', function(peer, message) { var tx = new bitcore.Transaction(message.transaction); - if (validTx(tx)) { + if (self.validTx(tx)) { return self._cache.set(tx.id, tx); } return self._operations.push({ diff --git a/lib/services/wallet-api/encoding.js b/lib/services/wallet-api/encoding.js new file mode 100644 index 00000000..2ca7da94 --- /dev/null +++ b/lib/services/wallet-api/encoding.js @@ -0,0 +1,237 @@ +'use strict'; + +var bitcore = require('bitcore-lib'); +var BufferReader = bitcore.encoding.BufferReader; + +function Encoding(servicePrefix) { + this.servicePrefix = servicePrefix; +} + +Encoding.prototype.encodeWalletTransactionKey = function(walletId, height) { + var buffers = [this.servicePrefix]; + + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + + buffers.push(walletIdSizeBuffer); + buffers.push(walletIdBuffer); + + if(height !== undefined) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + buffers.push(heightBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeWalletTransactionKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(1); + + var walletSize = reader.readUInt8(); + var walletId = reader.read(walletSize).toString('utf8'); + var height = reader.readUInt32BE(); + var blockIndex = reader.readUInt32BE(); + + return { + walletId: walletId, + height: height, + blockIndex: blockIndex + }; +}; + +Encoding.prototype.encodeWalletTransactionValue = function(txid) { + return new Buffer(txid, 'hex'); +}; + +Encoding.prototype.decodeWalletTransactionValue = function(buffer) { + return buffer.toString('hex'); +}; + +Encoding.prototype.encodeWalletUtxoKey = function(walletId, txid, outputIndex) { + var buffers = [this.servicePrefix]; + + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + + buffers.push(walletIdSizeBuffer); + buffers.push(walletIdBuffer); + + if(txid) { + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + } + + if(outputIndex !== undefined) { + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + buffers.push(outputIndexBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeWalletUtxoKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(1); + + var walletIdSize = reader.readUInt8(); + var walletId = reader.read(walletIdSize).toString('utf8'); + var txid = reader.read(32).toString('hex'); + var outputIndex = reader.readUInt32BE(); + return { + walletId: walletId, + txid: txid, + outputIndex: outputIndex + }; +}; + +Encoding.prototype.encodeWalletUtxoValue = function(height, satoshis, scriptBuffer) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + var satoshisBuffer = new Buffer(8); + satoshisBuffer.writeDoubleBE(satoshis); + return Buffer.concat([height, satoshisBuffer, scriptBuffer]); +}; + +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); + return { + height: height, + satoshis: satoshis, + script: scriptBuffer + }; +}; + +Encoding.prototype.encodeWalletUtxoSatoshisKey = function(walletId, satoshis, txid, outputIndex) { + var buffers = [this.servicePrefix]; + + var walletIdSizeBuffer = new Buffer(1); + walletIdSizeBuffer.writeUInt8(walletId.length); + var walletIdBuffer = new Buffer(walletId, 'utf8'); + + buffers.push(walletIdSizeBuffer); + buffers.push(walletIdBuffer); + + if(satoshis !== undefined) { + var satoshisBuffer = new Buffer(8); + satoshisBuffer.writeUInt32BE(satoshis); + buffers.push(satoshisBuffer); + } + + if(txid) { + var txidBuffer = new Buffer(txid, 'hex'); + buffers.push(txidBuffer); + } + + if(outputIndex !== undefined) { + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + buffers.push(outputIndexBuffer); + } + + return Buffer.concat(buffers); +}; + +Encoding.prototype.decodeWalletUtxoSatoshisKey = function(buffer) { + var reader = new BufferReader(buffer); + reader.read(1); + + var walletIdSizeBuffer = reader.readUInt8(); + var walletId = reader.read(walletIdSizeBuffer).toString('utf8'); + var satoshis = reader.readDoubleBE(); + var txid = reader.read(32).toString('hex'); + var outputIndex = reader.readUInt32BE(); + return { + walletId: walletId, + satoshis: satoshis, + txid: txid, + outputIndex: outputIndex + }; +}; + +Encoding.prototype.encodeWalletUtxoSatoshisValue = function(height, scriptBuffer) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + return Buffer.concat([height, scriptBuffer]); +}; + +Encoding.prototype.decodeWalletUtxoSatoshisValue = function(buffer) { + var reader = new BufferReader(buffer); + var height = reader.readUInt32BE(); + var scriptBuffer = reader.read(buffer.length - 4); + return { + height: height, + script: scriptBuffer + }; +}; + +Encoding.prototype.encodeWalletAddressesKey = function(walletId) { + var prefix = new Buffer('00', 'hex'); + var walletIdBuffer = new Buffer(walletId, 'hex'); + return Buffer.concat([this.servicePrefix, prefix, walletIdBuffer]); +}; + +Encoding.prototype.decodeWalletAddressesKey = function(buffer) { + return buffer.slice(3).toString('hex'); +}; + +Encoding.prototype.encodeWalletAddressesValue = function(addresses) { + var bufferList = []; + var addressesLengthBuffer = new Buffer(4); + addressesLengthBuffer.writeUInt32BE(addresses.length); + bufferList.push(addressesLengthBuffer); + for(var i = 0; i < addresses.length; i++) { + var addressSizeBuffer = new Buffer(1); + addressSizeBuffer.writeUInt8(addresses[i].length); + bufferList.push(addressSizeBuffer); + bufferList.push(new Buffer(addresses[i], 'utf8')); + } + + return Buffer.concat(bufferList); +}; + +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); + 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]); +}; + +Encoding.prototype.decodeWalletBalanceKey = function(buffer) { + return buffer.slice(3).toString('hex'); +}; + +Encoding.prototype.encodeWalletBalanceValue = function(balance) { + var balanceBuffer = new Buffer(8); + balanceBuffer.writeUInt32BE(balance); + return balanceBuffer; +}; + +Encoding.prototype.decodeWalletBalanceValue = function(buffer) { + var reader = new BufferReader(buffer); + var balance = reader.readDoubleBE(); + + return balance; +}; + +module.exports = Encoding; + diff --git a/lib/services/wallet-api/index.js b/lib/services/wallet-api/index.js index 1725feac..93ca49c3 100644 --- a/lib/services/wallet-api/index.js +++ b/lib/services/wallet-api/index.js @@ -13,7 +13,7 @@ var utils = require('./utils'); var _ = require('lodash'); var bodyParser = require('body-parser'); var LRU = require('lru-cache'); -var Encoding = require('../../encoding'); // TODO this needs to be split out by service +var Encoding = require('./encoding'); var WalletService = function(options) { BaseService.call(this, options); @@ -40,6 +40,7 @@ WalletService.dependencies = [ WalletService.prototype.getAPIMethods = function() { return []; }; + WalletService.prototype.start = function(callback) { var self = this; @@ -108,7 +109,8 @@ WalletService.prototype.blockHandler = function(block, connectBlock, callback) { var walletIds = self._addressMap[address]; - walletIds.forEach(function(walletId) { + for(var i = 0; i < walletIds.length; i++) { + var walletId = walletIds[i]; walletIdsNeedingUpdate[walletId] = true; operations.push({ @@ -128,7 +130,7 @@ WalletService.prototype.blockHandler = function(block, connectBlock, callback) { } else { self.balances[walletId] -= output.satoshis; } - }); + } } if(tx.isCoinbase()) { @@ -235,13 +237,14 @@ WalletService.prototype.concurrentBlockHandler = function(block, connectBlock, c var walletIds = self._addressMap[address]; - walletIds.forEach(function(walletId) { + for(var j = 0; j < walletIds.length; j++) { + var walletId = walletIds[i]; operations.push({ type: action, key: self._encoding.encodeWalletTransactionKey(walletId, block.__height), value: self._encoding.encodeWalletTransactionValue(tx.id) }); - }); + } } if(tx.isCoinbase()) { @@ -265,13 +268,14 @@ WalletService.prototype.concurrentBlockHandler = function(block, connectBlock, c var inputWalletIds = self._addressMap[inputAddress]; - inputWalletIds.forEach(function(walletId) { + for(var k = 0; k < inputWalletIds.length; k++) { + var inputWalletId = inputWalletIds[inputIndex]; operations.push({ type: action, - key: self._encoding.encodeWalletTransactionKey(walletId, block.__height), + key: self._encoding.encodeWalletTransactionKey(inputWalletId, block.__height), value: self._encoding.encodeWalletTransactionValue(tx.id) }); - }); + } } } setImmediate(function() { @@ -569,6 +573,7 @@ WalletService.prototype._getTransactions = function(walletId, options, callback) end: options.end || Math.pow(2, 32) - 1 }; var key = walletId + opts.start + opts.end; + var transactions; function finish(transactions) { var from = options.from || 0; @@ -584,7 +589,7 @@ WalletService.prototype._getTransactions = function(walletId, options, callback) if(err) { return callback(err); } - transactions = transaction.concat(mempoolTxs); + transactions = transactions.concat(mempoolTxs); callback(null, transactions.slice(from, to), transactions.length); }); }); diff --git a/lib/services/web.js b/lib/services/web/index.js similarity index 99% rename from lib/services/web.js rename to lib/services/web/index.js index 850accb0..ab6d8c07 100644 --- a/lib/services/web.js +++ b/lib/services/web/index.js @@ -8,10 +8,10 @@ var bodyParser = require('body-parser'); var socketio = require('socket.io'); var inherits = require('util').inherits; -var BaseService = require('../service'); +var BaseService = require('../../service'); var bitcore = require('bitcore-lib'); var _ = bitcore.deps._; -var index = require('../'); +var index = require('../../'); var log = index.log;