From f88eee5a1cbec2f3033b06e0ace7f47861cd04ed Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 14 Sep 2015 09:01:51 -0400 Subject: [PATCH] Improve db storage efficiency by ~2 times Encodes and decodes keys and values for leveldb storage more efficiently. --- lib/services/address/index.js | 257 +++++++++++++++++++--------- test/services/address/index.unit.js | 116 ++++--------- 2 files changed, 215 insertions(+), 158 deletions(-) diff --git a/lib/services/address/index.js b/lib/services/address/index.js index 82eb45272..e99a3dae4 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -10,6 +10,7 @@ var bitcore = require('bitcore'); var $ = bitcore.util.preconditions; var _ = bitcore.deps._; var Hash = bitcore.crypto.Hash; +var BufferReader = bitcore.encoding.BufferReader; var EventEmitter = require('events').EventEmitter; var PublicKey = bitcore.PublicKey; var Address = bitcore.Address; @@ -34,10 +35,13 @@ AddressService.dependencies = [ ]; AddressService.PREFIXES = { - OUTPUTS: 'outs', - SPENTS: 'sp' + OUTPUTS: new Buffer('32', 'hex'), + SPENTS: new Buffer('33', 'hex') }; +AddressService.SPACER_MIN = new Buffer('00', 'hex'); +AddressService.SPACER_MAX = new Buffer('ff', 'hex'); + AddressService.prototype.getAPIMethods = function() { return [ ['getBalance', this, this.getBalance, 2], @@ -153,6 +157,7 @@ AddressService.prototype._extractAddressInfoFromScript = function(script) { AddressService.prototype.blockHandler = function(block, addOutput, callback) { var txs = block.transactions; + var height = block.__height; var action = 'put'; if (!addOutput) { @@ -188,43 +193,28 @@ AddressService.prototype.blockHandler = function(block, addOutput, callback) { continue; } - addressInfo.hashHex = addressInfo.hashBuffer.toString('hex'); - // We need to use the height for indexes (and not the timestamp) because the // the timestamp has unreliable sequential ordering. The next block // can have a time that is previous to the previous block (however not // less than the mean of the 11 previous blocks) and not greater than 2 // hours in the future. - var height = block.__height; - - var scriptHex = output._scriptBuffer.toString('hex'); - - // To lookup outputs by address and height - var key = [ - AddressService.PREFIXES.OUTPUTS, - addressInfo.hashHex, - height, - txid, - outputIndex - ].join('-'); - - // TODO use buffers directly to save on disk storage - - var value = [output.satoshis, scriptHex].join(':'); - + var key = this._encodeOutputKey(addressInfo.hashBuffer, height, txid, outputIndex); + var value = this._encodeOutputValue(output.satoshis, output._scriptBuffer); operations.push({ type: action, key: key, value: value }); + addressInfo.hashHex = addressInfo.hashBuffer.toString('hex'); + // Collect data for subscribers if (txmessages[addressInfo.hashHex]) { txmessages[addressInfo.hashHex].outputIndexes.push(outputIndex); } else { txmessages[addressInfo.hashHex] = { tx: tx, - height: block.__height, + height: height, outputIndexes: [outputIndex], addressInfo: addressInfo, timestamp: block.header.timestamp @@ -247,30 +237,19 @@ AddressService.prototype.blockHandler = function(block, addOutput, callback) { for(var inputIndex = 0; inputIndex < inputs.length; inputIndex++) { var input = inputs[inputIndex]; - - var inputHashBuffer; + var inputHash; if (input.script.isPublicKeyHashIn()) { - inputHashBuffer = Hash.sha256ripemd160(input.script.chunks[1].buf); + inputHash = Hash.sha256ripemd160(input.script.chunks[1].buf); } else if (input.script.isScriptHashIn()) { - inputHashBuffer = Hash.sha256ripemd160(input.script.chunks[input.script.chunks.length - 1].buf); + inputHash = Hash.sha256ripemd160(input.script.chunks[input.script.chunks.length - 1].buf); } else { continue; } // To be able to query inputs by address and spent height - var inputKey = [ - AddressService.PREFIXES.SPENTS, - inputHashBuffer.toString('hex'), - block.__height, - input.prevTxId.toString('hex'), - input.outputIndex - ].join('-'); - - var inputValue = [ - txid, - inputIndex - ].join(':'); + var inputKey = this._encodeInputKey(inputHash, height, input.prevTxId, input.outputIndex); + var inputValue = this._encodeInputValue(txid, inputIndex); operations.push({ type: action, @@ -285,6 +264,104 @@ AddressService.prototype.blockHandler = function(block, addOutput, callback) { }); }; +AddressService.prototype._encodeOutputKey = function(hashBuffer, height, txid, outputIndex) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + var key = Buffer.concat([ + AddressService.PREFIXES.OUTPUTS, + hashBuffer, + AddressService.SPACER_MIN, + heightBuffer, + new Buffer(txid, 'hex'), //TODO get buffer directly from tx + outputIndexBuffer + ]); + return key; +}; + +AddressService.prototype._decodeOutputKey = function(buffer) { + var reader = new BufferReader(buffer); + var prefix = reader.read(1); + var hashBuffer = reader.read(20); + var spacer = reader.read(1); + var height = reader.readUInt32BE(); + var txid = reader.read(32); + var outputIndex = reader.readUInt32BE(); + return { + prefix: prefix, + hashBuffer: hashBuffer, + height: height, + txid: txid, + outputIndex: outputIndex + }; +}; + +AddressService.prototype._encodeOutputValue = function(satoshis, scriptBuffer) { + var satoshisBuffer = new Buffer(8); + satoshisBuffer.writeDoubleBE(satoshis); + return Buffer.concat([satoshisBuffer, scriptBuffer]); +}; + +AddressService.prototype._decodeOutputValue = function(buffer) { + var satoshis = buffer.readDoubleBE(0); + var scriptBuffer = buffer.slice(8, buffer.length); + return { + satoshis: satoshis, + scriptBuffer: scriptBuffer + }; +}; + +AddressService.prototype._encodeInputKey = function(hashBuffer, height, prevTxIdBuffer, outputIndex) { + var heightBuffer = new Buffer(4); + heightBuffer.writeUInt32BE(height); + var outputIndexBuffer = new Buffer(4); + outputIndexBuffer.writeUInt32BE(outputIndex); + return Buffer.concat([ + AddressService.PREFIXES.SPENTS, + hashBuffer, + AddressService.SPACER_MIN, + heightBuffer, + prevTxIdBuffer, + outputIndexBuffer + ]); +}; + +AddressService.prototype._decodeInputKey = function(buffer) { + var reader = new BufferReader(buffer); + var prefix = reader.read(1); + var hashBuffer = reader.read(20); + var spacer = reader.read(1); + var height = reader.readUInt32BE(); + var prevTxId = reader.read(32); + var outputIndex = reader.readUInt32BE(); + return { + prefix: prefix, + hashBuffer: hashBuffer, + height: height, + prevTxId: prevTxId, + outputIndex: outputIndex + }; +}; + +AddressService.prototype._encodeInputValue = function(txid, inputIndex) { + var inputIndexBuffer = new Buffer(4); + inputIndexBuffer.writeUInt32BE(inputIndex); + return Buffer.concat([ + new Buffer(txid, 'hex'), + inputIndexBuffer + ]); +}; + +AddressService.prototype._decodeInputValue = function(buffer) { + var txid = buffer.slice(0, 32); + var inputIndex = buffer.readUInt32BE(32); + return { + txid: txid, + inputIndex: inputIndex + }; +}; + /** * @param {Object} obj * @param {Transaction} obj.tx - The transaction @@ -424,45 +501,56 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) { var inputs = []; var stream; - var hashHex = bitcore.Address(addressStr).hashBuffer.toString('hex'); + var hashBuffer = bitcore.Address(addressStr).hashBuffer; if (options.start && options.end) { - // The positions will be flipped because the end position should be greater - // than the starting position for the stream, and we'll add one to the end key - // so that it's included in the results. + var endBuffer = new Buffer(4); + endBuffer.writeUInt32BE(options.end); - var endKey = [AddressService.PREFIXES.SPENTS, hashHex, options.start + 1].join('-'); - var startKey = [AddressService.PREFIXES.SPENTS, hashHex, options.end].join('-'); + var startBuffer = new Buffer(4); + startBuffer.writeUInt32BE(options.start + 1); stream = this.node.services.db.store.createReadStream({ - start: startKey, - end: endKey + gte: Buffer.concat([ + AddressService.PREFIXES.SPENTS, + hashBuffer, + AddressService.SPACER_MIN, + endBuffer + ]), + lte: Buffer.concat([ + AddressService.PREFIXES.SPENTS, + hashBuffer, + AddressService.SPACER_MIN, + startBuffer + ]), + valueEncoding: 'binary', + keyEncoding: 'binary' }); } else { - var allKey = [AddressService.PREFIXES.SPENTS, hashHex].join('-'); + var allKey = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer]); stream = this.node.services.db.store.createReadStream({ - start: allKey, - end: allKey + '~' + gte: Buffer.concat([allKey, AddressService.SPACER_MIN]), + lte: Buffer.concat([allKey, AddressService.SPACER_MAX]), + valueEncoding: 'binary', + keyEncoding: 'binary' }); } stream.on('data', function(data) { - var key = data.key.split('-'); - var value = data.value.split(':'); - - var blockHeight = Number(key[2]); + var key = self._decodeInputKey(data.key); + var value = self._decodeInputValue(data.value); - var output = { + var input = { address: addressStr, - txid: value[0], - inputIndex: Number(value[1]), - height: blockHeight, - confirmations: self.node.services.db.tip.__height - blockHeight + 1 + txid: value.txid.toString('hex'), + inputIndex: value.inputIndex, + height: key.height, + confirmations: self.node.services.db.tip.__height - key.height + 1 }; - inputs.push(output); + inputs.push(input); }); @@ -502,44 +590,57 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) { $.checkArgument(_.isObject(options), 'Second argument is expected to be an options object.'); $.checkArgument(_.isFunction(callback), 'Third argument is expected to be a callback function.'); - var hashHex = bitcore.Address(addressStr).hashBuffer.toString('hex'); + var hashBuffer = bitcore.Address(addressStr).hashBuffer; var outputs = []; var stream; if (options.start && options.end) { - // The positions will be flipped because the end position should be greater - // than the starting position for the stream, and we'll add one to the end key - // so that it's included in the results. - var endKey = [AddressService.PREFIXES.OUTPUTS, hashHex, options.start + 1].join('-'); - var startKey = [AddressService.PREFIXES.OUTPUTS, hashHex, options.end].join('-'); + var startBuffer = new Buffer(4); + startBuffer.writeUInt32BE(options.start + 1); + var endBuffer = new Buffer(4); + endBuffer.writeUInt32BE(options.end); stream = this.node.services.db.store.createReadStream({ - start: startKey, - end: endKey + gte: Buffer.concat([ + AddressService.PREFIXES.OUTPUTS, + hashBuffer, + AddressService.SPACER_MIN, + endBuffer + ]), + lte: Buffer.concat([ + AddressService.PREFIXES.OUTPUTS, + hashBuffer, + AddressService.SPACER_MIN, + startBuffer + ]), + valueEncoding: 'binary', + keyEncoding: 'binary' }); } else { - var allKey = [AddressService.PREFIXES.OUTPUTS, hashHex].join('-'); + var allKey = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer]); stream = this.node.services.db.store.createReadStream({ - start: allKey, - end: allKey + '~' + gte: Buffer.concat([allKey, AddressService.SPACER_MIN]), + lte: Buffer.concat([allKey, AddressService.SPACER_MAX]), + valueEncoding: 'binary', + keyEncoding: 'binary' }); } stream.on('data', function(data) { - var key = data.key.split('-'); - var value = data.value.split(':'); + var key = self._decodeOutputKey(data.key); + var value = self._decodeOutputValue(data.value); var output = { address: addressStr, - txid: key[3], - outputIndex: Number(key[4]), - height: Number(key[2]), - satoshis: Number(value[0]), - script: value[1], - confirmations: self.node.services.db.tip.__height - Number(key[2]) + 1 + txid: key.txid.toString('hex'), + outputIndex: key.outputIndex, + height: key.height, + satoshis: value.satoshis, + script: value.scriptBuffer.toString('hex'), + confirmations: self.node.services.db.tip.__height - key.height + 1 }; outputs.push(output); diff --git a/test/services/address/index.unit.js b/test/services/address/index.unit.js index 468a75a9d..4aac31b53 100644 --- a/test/services/address/index.unit.js +++ b/test/services/address/index.unit.js @@ -108,53 +108,6 @@ describe('Address Service', function() { var am; var testBlock = bitcore.Block.fromString(blockData); - var data = [ - { - key: { - hashHex: bitcore.Address('1F1MAvhTKg2VG29w8cXsiSN2PJ8gSsrJw').hashBuffer.toString('hex'), - height: 345003, - txid: 'fdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e16923', - outputIndex: 0 - }, - value: { - satoshis: 2502227470, - script: '76a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac', - blockHeight: 345003 - } - }, - { - key: { - hashHex: bitcore.Address('1Q8ec8kG7c7HqgK7uSzQyWsX9tzepRcKEL').hashBuffer.toString('hex'), - height: 345003, - prevTxId: '3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a9', - prevOutputIndex: 32 - }, - value: { - txid: '5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca', - inputIndex: 0 - } - }, - { - key: { - hashHex: bitcore.Address('1Ep5LA4T6Y7zaBPiwruUJurjGFvCJHzJhm').hashBuffer.toString('hex'), - height: 345003, - txid: 'e66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d', - outputIndex: 1 - }, - value: { - satoshis: 3100000, - script: '76a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac', - blockHeight: 345003 - } - } - ]; - var key0 = data[0].key; - var value0 = data[0].value; - var key3 = data[1].key; - var value3 = data[1].value; - var key64 = data[2].key; - var value64 = data[2].value; - before(function() { am = new AddressService({node: mocknode}); am.node.network = Networks.livenet; @@ -173,17 +126,14 @@ describe('Address Service', function() { should.not.exist(err); operations.length.should.equal(81); operations[0].type.should.equal('put'); - var expected0 = ['outs', key0.hashHex, key0.height, key0.txid, key0.outputIndex].join('-'); - operations[0].key.should.equal(expected0); - operations[0].value.should.equal([value0.satoshis, value0.script].join(':')); + operations[0].key.toString('hex').should.equal('3202a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b00000543abfdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e1692300000000'); + operations[0].value.toString('hex').should.equal('41e2a49ec1c0000076a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac'); operations[3].type.should.equal('put'); - var expected3 = ['sp', key3.hashHex, key3.height, key3.prevTxId, key3.prevOutputIndex].join('-'); - operations[3].key.should.equal(expected3); - operations[3].value.should.equal([value3.txid, value3.inputIndex].join(':')); + operations[3].key.toString('hex').should.equal('33fdbd324b28ea69e49c998816407dc055fb81d06e00000543ab3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020'); + operations[3].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000'); operations[64].type.should.equal('put'); - var expected64 = ['outs', key64.hashHex, key64.height, key64.txid, key64.outputIndex].join('-'); - operations[64].key.should.equal(expected64); - operations[64].value.should.equal([value64.satoshis, value64.script].join(':')); + operations[64].key.toString('hex').should.equal('329780ccd5356e2acc0ee439ee04e0fe69426c752800000543abe66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d00000001'); + operations[64].value.toString('hex').should.equal('4147a6b00000000076a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac'); done(); }); }); @@ -199,14 +149,14 @@ describe('Address Service', function() { should.not.exist(err); operations.length.should.equal(81); operations[0].type.should.equal('del'); - operations[0].key.should.equal(['outs', key0.hashHex, key0.height, key0.txid, key0.outputIndex].join('-')); - operations[0].value.should.equal([value0.satoshis, value0.script].join(':')); + operations[0].key.toString('hex').should.equal('3202a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b00000543abfdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e1692300000000'); + operations[0].value.toString('hex').should.equal('41e2a49ec1c0000076a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac'); operations[3].type.should.equal('del'); - operations[3].key.should.equal(['sp', key3.hashHex, key3.height, key3.prevTxId, key3.prevOutputIndex].join('-')); - operations[3].value.should.equal([value3.txid, value3.inputIndex].join(':')); + operations[3].key.toString('hex').should.equal('33fdbd324b28ea69e49c998816407dc055fb81d06e00000543ab3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020'); + operations[3].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000'); operations[64].type.should.equal('del'); - operations[64].key.should.equal(['outs', key64.hashHex, key64.height, key64.txid, key64.outputIndex].join('-')); - operations[64].value.should.equal([value64.satoshis, value64.script].join(':')); + operations[64].key.toString('hex').should.equal('329780ccd5356e2acc0ee439ee04e0fe69426c752800000543abe66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d00000001'); + operations[64].value.toString('hex').should.equal('4147a6b00000000076a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac'); done(); }); }); @@ -442,7 +392,7 @@ describe('Address Service', function() { describe('#getInputs', function() { var am; var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W'; - var hashHex = bitcore.Address(address).hashBuffer.toString('hex'); + var hashBuffer = bitcore.Address(address).hashBuffer; var db = { tip: { __height: 1 @@ -470,8 +420,10 @@ describe('Address Service', function() { var createReadStreamCallCount = 0; am.node.services.db.store = { createReadStream: function(ops) { - ops.start.should.equal([AddressService.PREFIXES.SPENTS, hashHex, 12].join('-')); - ops.end.should.equal([AddressService.PREFIXES.SPENTS, hashHex, 16].join('-')); + var gte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('000000000c', 'hex')]); + ops.gte.toString('hex').should.equal(gte.toString('hex')); + var lte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('0000000010', 'hex')]); + ops.lte.toString('hex').should.equal(lte.toString('hex')); createReadStreamCallCount++; return testStream; } @@ -490,8 +442,8 @@ describe('Address Service', function() { }); createReadStreamCallCount.should.equal(1); var data = { - key: ['sp', address, '15', '125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87', '1'].join('-'), - value: ['3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae7', '0'].join(':') + key: new Buffer('33038a213afdfc551fc658e9a2a58a86e98d69b687000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'), + value: new Buffer('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000000', 'hex') }; testStream.emit('data', data); testStream.emit('close'); @@ -504,8 +456,10 @@ describe('Address Service', function() { var createReadStreamCallCount = 0; am.node.services.db.store = { createReadStream: function(ops) { - ops.start.should.equal([AddressService.PREFIXES.SPENTS, hashHex].join('-')); - ops.end.should.equal([AddressService.PREFIXES.SPENTS, hashHex].join('-') + '~'); + var gte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('00', 'hex')]); + ops.gte.toString('hex').should.equal(gte.toString('hex')); + var lte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('ff', 'hex')]); + ops.lte.toString('hex').should.equal(lte.toString('hex')); createReadStreamCallCount++; return testStream; } @@ -524,8 +478,8 @@ describe('Address Service', function() { }); createReadStreamCallCount.should.equal(1); var data = { - key: ['sp', address, '15', '125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87', '1'].join('-'), - value: ['3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae7', '0'].join(':') + key: new Buffer('33038a213afdfc551fc658e9a2a58a86e98d69b687000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'), + value: new Buffer('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000000', 'hex') }; testStream.emit('data', data); testStream.emit('close'); @@ -553,7 +507,7 @@ describe('Address Service', function() { describe('#getOutputs', function() { var am; var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W'; - var hashHex = bitcore.Address('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W').hashBuffer.toString('hex'); + var hashBuffer = bitcore.Address('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W').hashBuffer; var db = { tip: { __height: 1 @@ -585,8 +539,10 @@ describe('Address Service', function() { var createReadStreamCallCount = 0; am.node.services.db.store = { createReadStream: function(ops) { - ops.start.should.equal([AddressService.PREFIXES.OUTPUTS, hashHex, 12].join('-')); - ops.end.should.equal([AddressService.PREFIXES.OUTPUTS, hashHex, 16].join('-')); + var gte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, new Buffer('000000000c', 'hex')]); + ops.gte.toString('hex').should.equal(gte.toString('hex')); + var lte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, new Buffer('0000000010', 'hex')]); + ops.lte.toString('hex').should.equal(lte.toString('hex')); createReadStreamCallCount++; return testStream; } @@ -607,8 +563,8 @@ describe('Address Service', function() { }); createReadStreamCallCount.should.equal(1); var data = { - key: ['outs', address, '15', '125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87', '1'].join('-'), - value: ['4527773864', '76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac'].join(':') + key: new Buffer('32038a213afdfc551fc658e9a2a58a86e98d69b687000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'), + value: new Buffer('41f0de058a80000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex') }; testStream.emit('data', data); testStream.emit('close'); @@ -655,13 +611,13 @@ describe('Address Service', function() { }); var data1 = { - key: ['outs', address, 345000, '125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87', '1'].join('-'), - value: ['4527773864', '76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac'].join(':') + key: new Buffer('32038a213afdfc551fc658e9a2a58a86e98d69b68700000543a8125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'), + value: new Buffer('41f0de058a80000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex') }; var data2 = { - key: ['outs', address, 345004, '3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae7', '2'].join('-'), - value: ['10000', '76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac'].join(':') + key: new Buffer('32038a213afdfc551fc658e9a2a58a86e98d69b68700000543ac3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000002', 'hex'), + value: new Buffer('40c388000000000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex') }; readStream1.emit('data', data1);