This commit is contained in:
Chris Kleeschulte 2017-05-26 16:19:49 -04:00
parent d6f1f26469
commit 443688face
3 changed files with 127 additions and 28 deletions

View File

@ -1,15 +1,17 @@
'use strict';
var assert = require('assert');
var bitcore = require('bitcore-lib');
var BufferReader = bitcore.encoding.BufferReader;
function Encoding(servicePrefix) {
this.servicePrefix = servicePrefix;
this.nonP2PKPrefix = new Buffer('00', 'hex');
this.P2PKPrefix = new Buffer('01', 'hex');
}
Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) {
var prefix = new Buffer('01', 'hex');
var buffers = [this.servicePrefix, prefix];
var buffers = [this.servicePrefix, this.nonP2PKPrefix];
var addressSizeBuffer = new Buffer(1);
addressSizeBuffer.writeUInt8(address.length);
@ -63,5 +65,56 @@ Encoding.prototype.decodeUtxoIndexValue = function(buffer) {
};
};
Encoding.prototype.encodeP2PKUtxoIndexKey = function(txid, outputIndex) {
var buffers = [this.servicePrefix, this.P2PKPrefix];
assert(txid && txid.length === 64, 'Txid required');
assert(outputIndex >= 0, 'outputIndex required');
var txidBuffer = new Buffer(txid);
buffers.push(txidBuffer);
var outputIndexBuffer = new Buffer(4);
outputIndexBuffer.writeUInt32BE(outputIndex);
buffers.push(outputIndexBuffer);
return Buffer.concat(buffers);
};
Encoding.prototype.decodeP2PKUtxoIndexKey = 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.encodeP2PKUtxoIndexValue = 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.decodeP2PKUtxoIndexValue = function(buffer) {
var height = buffer.readUInt32BE();
var satoshis = buffer.readDoubleBE(4);
var scriptBuffer = buffer.slice(12);
return {
height: height,
satoshis: satoshis,
script: scriptBuffer
};
};
module.exports = Encoding;

View File

@ -3,8 +3,9 @@
var BaseService = require('../../service');
var inherits = require('util').inherits;
var Encoding = require('./encoding');
var LRU = require('lru-cache');
var utils = require('../../utils');
var index = require('../../');
var log = index.log;
function UtxoService(options) {
BaseService.call(this, options);
@ -79,7 +80,7 @@ UtxoService.prototype.getUtxosForAddress = function(address, callback) {
address: address,
height: value.height,
satoshis: value.satoshis,
script: value.scriptBuffer
script: value.script
});
});
@ -92,17 +93,32 @@ UtxoService.prototype._processInputs = function(tx, inputs, connect) {
var operations = [];
for(var i = 0; i < inputs.length; i++) {
var input = inputs[i];
var key = input.prevHash + input.outputIndex;
var input = inputs[i];
if (input.prevTxId === tx.hash) {
this._exlusionIndexes.push(i);
continue;
}
var ops = this._moveOutput(key, connect);
operations = operations.concat(ops);
var key = this._getOperationsKey({
script: input.script,
txid: input.prevTxId.toString('hex'),
index: input.outputIndex
});
if (key) {
var operation = connect ? {
type: 'del',
key: key
} : {
type: 'put',
key: key,
value: new Buffer('00', 'hex')
};
operations.push(operation);
}
}
return operations;
@ -115,42 +131,70 @@ UtxoService.prototype._processOutputs = function(tx, outputs, block, connect) {
for(var i = 0; i < outputs.length; i++) {
var output = outputs[i];
var key = tx.hash + i;
if (this._exclusionIndexes.indexOf(i) > -1) {
continue;
}
var action = connect ? 'put' : 'del';
operations = operations.concat(
{ action: action,
key: this._getOperationsKey(key, output),
value: this._getOperationsValue({
height: block.__height,
satoshis: output.satoshis,
script: output.script
})
}
);
var key = this._getOperationsKey({
script: output.script,
txid: tx.id,
index: i
});
var value = this._getOperationsValue({
height: block.__height,
satoshis: output.satoshis,
script: output.script
});
if (key && value) {
var operation = connect ? {
type: 'put',
key: key,
value: value
} : {
type: 'del',
key: key,
value: value
};
operations.push(operation);
}
}
return operations;
};
UtxoService.prototype._moveOutput = function(key, connect) {
UtxoService.prototype._getOperationsKey = function(io) {
if (connect) {
return { action: 'del', key: key };
var address = utils.getAddressStringFromScript(io.script, this.node.network);
if (!address) {
var key = this._tryP2PKOperation(io);
if (key) {
return key;
}
}
return { action: 'put', key: key, value: null };
if (!address) {
log.debug('could not determine address for script: ' + io.script.toString());
return;
}
return this.encoding.encodeUtxoIndexKey(address, io.txid, io.index);
};
UtxoService.prototype._getOperationsKey = function(key, output) {
var address = utils.getAddressStringFromScript(output.script, this.node.network);
return this.encoding.encodeUtxoIndexKey(address, key.slice(0, 64), parseInt(key.slice(64)));
UtxoService.prototype._tryP2PKOperation = function(io) {
// checking for a scriptSig that has one signature
var sig = io.script.chunks[0];
if (sig && (sig.len > 69 && sig.len < 75)) {
return this.encoding.encodeP2PKUtxoIndexKey(io.txid, io.index);
}
};
UtxoService.prototype._getOperationsValue = function(value) {

View File

@ -121,6 +121,7 @@ describe('Utxo Operations', function() {
utils.waitForBitcoinReady.bind(utils, self.opts),
utils.unlockWallet.bind(utils, self.opts),
utils.setupInitialTxs.bind(utils, self.opts),
utils.sendTxs.bind(utils, self.opts),
utils.startBitcoreNode.bind(utils, self.opts),
utils.waitForBitcoreNode.bind(utils, self.opts)
], done);
@ -140,6 +141,8 @@ describe('Utxo Operations', function() {
res = JSON.parse(res);
expect(res.address).to.equal(address);
expect(res.utxos.length).equal(1);
expect(Object.keys(res.utxos[0])).to.deep.equal([ 'txid', 'outputIndex', 'address', 'height', 'satoshis', 'script' ]);
next(null, res.utxos);
});
}, function(err, utxos) {
@ -147,7 +150,6 @@ describe('Utxo Operations', function() {
if(err) {
return done(err);
}
console.log('done');
done();