Fix #377; db must contain hash type, not just hash.
Prevents erroneous crediting of all transactions to both the p2pkh and the corresponding p2sh address.
This commit is contained in:
parent
858182a346
commit
3214390d4c
@ -726,8 +726,9 @@ describe('Node Functionality', function() {
|
|||||||
node.services.bitcoind.sendTransaction(tx.serialize());
|
node.services.bitcoind.sendTransaction(tx.serialize());
|
||||||
|
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
var hashBuffer = bitcore.Address(address).hashBuffer;
|
var addrObj = node.services.address._getAddressInfo(address);
|
||||||
node.services.address._getOutputsMempool(address, hashBuffer, function(err, outs) {
|
node.services.address._getOutputsMempool(address, addrObj.hashBuffer,
|
||||||
|
addrObj.hashTypeBuffer, function(err, outs) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,6 +70,27 @@ AddressService.MEMPREFIXES = {
|
|||||||
SPENTSMAP: new Buffer('03', 'hex') // Query mempool for the input that spends an output
|
SPENTSMAP: new Buffer('03', 'hex') // Query mempool for the input that spends an output
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// To save space, we're only storing the PubKeyHash or ScriptHash in our index.
|
||||||
|
// To avoid intentional unspendable collisions, which have been seen on the blockchain,
|
||||||
|
// we must store the hash type (PK or Script) as well.
|
||||||
|
AddressService.HASH_TYPES = {
|
||||||
|
PUBKEY: new Buffer('01', 'hex'),
|
||||||
|
REDEEMSCRIPT: new Buffer('02', 'hex')
|
||||||
|
};
|
||||||
|
|
||||||
|
// Translates from our enum type back into the hash types returned by
|
||||||
|
// bitcore-lib/address.
|
||||||
|
AddressService.HASH_TYPES_READABLE = {
|
||||||
|
'01': 'pubkeyhash',
|
||||||
|
'02': 'scripthash'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trnaslates from address types to our enum type.
|
||||||
|
AddressService.HASH_TYPES_MAP = {
|
||||||
|
'pubkeyhash': AddressService.HASH_TYPES.PUBKEY,
|
||||||
|
'scripthash': AddressService.HASH_TYPES.REDEEMSCRIPT
|
||||||
|
};
|
||||||
|
|
||||||
AddressService.SPACER_MIN = new Buffer('00', 'hex');
|
AddressService.SPACER_MIN = new Buffer('00', 'hex');
|
||||||
AddressService.SPACER_MAX = new Buffer('ff', 'hex');
|
AddressService.SPACER_MAX = new Buffer('ff', 'hex');
|
||||||
|
|
||||||
@ -303,6 +324,7 @@ AddressService.prototype.updateMempoolIndex = function(tx, add, callback) {
|
|||||||
var outKey = Buffer.concat([
|
var outKey = Buffer.concat([
|
||||||
AddressService.MEMPREFIXES.OUTPUTS,
|
AddressService.MEMPREFIXES.OUTPUTS,
|
||||||
addressInfo.hashBuffer,
|
addressInfo.hashBuffer,
|
||||||
|
addressInfo.hashTypeBuffer,
|
||||||
txidBuffer,
|
txidBuffer,
|
||||||
outputIndexBuffer
|
outputIndexBuffer
|
||||||
]);
|
]);
|
||||||
@ -355,16 +377,20 @@ AddressService.prototype.updateMempoolIndex = function(tx, add, callback) {
|
|||||||
|
|
||||||
// Update input index
|
// Update input index
|
||||||
var inputHashBuffer;
|
var inputHashBuffer;
|
||||||
|
var inputHashType;
|
||||||
if (input.script.isPublicKeyHashIn()) {
|
if (input.script.isPublicKeyHashIn()) {
|
||||||
inputHashBuffer = Hash.sha256ripemd160(input.script.chunks[1].buf);
|
inputHashBuffer = Hash.sha256ripemd160(input.script.chunks[1].buf);
|
||||||
|
inputHashType = AddressService.HASH_TYPES.PUBKEY;
|
||||||
} else if (input.script.isScriptHashIn()) {
|
} else if (input.script.isScriptHashIn()) {
|
||||||
inputHashBuffer = Hash.sha256ripemd160(input.script.chunks[input.script.chunks.length - 1].buf);
|
inputHashBuffer = Hash.sha256ripemd160(input.script.chunks[input.script.chunks.length - 1].buf);
|
||||||
|
inputHashType = AddressService.HASH_TYPES.REDEEMSCRIPT;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var inputKey = Buffer.concat([
|
var inputKey = Buffer.concat([
|
||||||
AddressService.MEMPREFIXES.SPENTS,
|
AddressService.MEMPREFIXES.SPENTS,
|
||||||
inputHashBuffer,
|
inputHashBuffer,
|
||||||
|
inputHashType,
|
||||||
input.prevTxId,
|
input.prevTxId,
|
||||||
inputOutputIndexBuffer
|
inputOutputIndexBuffer
|
||||||
]);
|
]);
|
||||||
@ -389,7 +415,6 @@ AddressService.prototype.updateMempoolIndex = function(tx, add, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.mempoolIndex.batch(operations, callback);
|
this.mempoolIndex.batch(operations, callback);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -401,16 +426,20 @@ AddressService.prototype.updateMempoolIndex = function(tx, add, callback) {
|
|||||||
AddressService.prototype._extractAddressInfoFromScript = function(script) {
|
AddressService.prototype._extractAddressInfoFromScript = function(script) {
|
||||||
var hashBuffer;
|
var hashBuffer;
|
||||||
var addressType;
|
var addressType;
|
||||||
|
var hashTypeBuffer;
|
||||||
if (script.isPublicKeyHashOut()) {
|
if (script.isPublicKeyHashOut()) {
|
||||||
hashBuffer = script.chunks[2].buf;
|
hashBuffer = script.chunks[2].buf;
|
||||||
|
hashTypeBuffer = AddressService.HASH_TYPES.PUBKEY;
|
||||||
addressType = Address.PayToPublicKeyHash;
|
addressType = Address.PayToPublicKeyHash;
|
||||||
} else if (script.isScriptHashOut()) {
|
} else if (script.isScriptHashOut()) {
|
||||||
hashBuffer = script.chunks[1].buf;
|
hashBuffer = script.chunks[1].buf;
|
||||||
|
hashTypeBuffer = AddressService.HASH_TYPES.REDEEMSCRIPT;
|
||||||
addressType = Address.PayToScriptHash;
|
addressType = Address.PayToScriptHash;
|
||||||
} else if (script.isPublicKeyOut()) {
|
} else if (script.isPublicKeyOut()) {
|
||||||
var pubkey = script.chunks[0].buf;
|
var pubkey = script.chunks[0].buf;
|
||||||
var address = Address.fromPublicKey(new PublicKey(pubkey), this.node.network);
|
var address = Address.fromPublicKey(new PublicKey(pubkey), this.node.network);
|
||||||
hashBuffer = address.hashBuffer;
|
hashBuffer = address.hashBuffer;
|
||||||
|
hashTypeBuffer = AddressService.HASH_TYPES.PUBKEY;
|
||||||
// pay-to-publickey doesn't have an address, however for compatibility
|
// pay-to-publickey doesn't have an address, however for compatibility
|
||||||
// purposes, we can create an address
|
// purposes, we can create an address
|
||||||
addressType = Address.PayToPublicKeyHash;
|
addressType = Address.PayToPublicKeyHash;
|
||||||
@ -419,6 +448,7 @@ AddressService.prototype._extractAddressInfoFromScript = function(script) {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
hashBuffer: hashBuffer,
|
hashBuffer: hashBuffer,
|
||||||
|
hashTypeBuffer: hashTypeBuffer,
|
||||||
addressType: addressType
|
addressType: addressType
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -474,7 +504,8 @@ AddressService.prototype.blockHandler = function(block, addOutput, callback) {
|
|||||||
// can have a time that is previous to the previous block (however not
|
// 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
|
// less than the mean of the 11 previous blocks) and not greater than 2
|
||||||
// hours in the future.
|
// hours in the future.
|
||||||
var key = this._encodeOutputKey(addressInfo.hashBuffer, height, txidBuffer, outputIndex);
|
var key = this._encodeOutputKey(addressInfo.hashBuffer, addressInfo.hashTypeBuffer,
|
||||||
|
height, txidBuffer, outputIndex);
|
||||||
var value = this._encodeOutputValue(output.satoshis, output._scriptBuffer);
|
var value = this._encodeOutputValue(output.satoshis, output._scriptBuffer);
|
||||||
operations.push({
|
operations.push({
|
||||||
type: action,
|
type: action,
|
||||||
@ -514,11 +545,14 @@ AddressService.prototype.blockHandler = function(block, addOutput, callback) {
|
|||||||
|
|
||||||
var input = inputs[inputIndex];
|
var input = inputs[inputIndex];
|
||||||
var inputHash;
|
var inputHash;
|
||||||
|
var inputHashType;
|
||||||
|
|
||||||
if (input.script.isPublicKeyHashIn()) {
|
if (input.script.isPublicKeyHashIn()) {
|
||||||
inputHash = Hash.sha256ripemd160(input.script.chunks[1].buf);
|
inputHash = Hash.sha256ripemd160(input.script.chunks[1].buf);
|
||||||
|
inputHashType = AddressService.HASH_TYPES.PUBKEY;
|
||||||
} else if (input.script.isScriptHashIn()) {
|
} else if (input.script.isScriptHashIn()) {
|
||||||
inputHash = Hash.sha256ripemd160(input.script.chunks[input.script.chunks.length - 1].buf);
|
inputHash = Hash.sha256ripemd160(input.script.chunks[input.script.chunks.length - 1].buf);
|
||||||
|
inputHashType = AddressService.HASH_TYPES.REDEEMSCRIPT;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -526,7 +560,7 @@ AddressService.prototype.blockHandler = function(block, addOutput, callback) {
|
|||||||
var prevTxIdBuffer = new Buffer(input.prevTxId, 'hex');
|
var prevTxIdBuffer = new Buffer(input.prevTxId, 'hex');
|
||||||
|
|
||||||
// To be able to query inputs by address and spent height
|
// To be able to query inputs by address and spent height
|
||||||
var inputKey = this._encodeInputKey(inputHash, height, prevTxIdBuffer, input.outputIndex);
|
var inputKey = this._encodeInputKey(inputHash, inputHashType, height, prevTxIdBuffer, input.outputIndex);
|
||||||
var inputValue = this._encodeInputValue(txidBuffer, inputIndex);
|
var inputValue = this._encodeInputValue(txidBuffer, inputIndex);
|
||||||
|
|
||||||
operations.push({
|
operations.push({
|
||||||
@ -563,7 +597,7 @@ AddressService.prototype._encodeSpentIndexSyncKey = function(txidBuffer, outputI
|
|||||||
return key.toString('binary');
|
return key.toString('binary');
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._encodeOutputKey = function(hashBuffer, height, txidBuffer, outputIndex) {
|
AddressService.prototype._encodeOutputKey = function(hashBuffer, hashTypeBuffer, height, txidBuffer, outputIndex) {
|
||||||
var heightBuffer = new Buffer(4);
|
var heightBuffer = new Buffer(4);
|
||||||
heightBuffer.writeUInt32BE(height);
|
heightBuffer.writeUInt32BE(height);
|
||||||
var outputIndexBuffer = new Buffer(4);
|
var outputIndexBuffer = new Buffer(4);
|
||||||
@ -571,6 +605,7 @@ AddressService.prototype._encodeOutputKey = function(hashBuffer, height, txidBuf
|
|||||||
var key = Buffer.concat([
|
var key = Buffer.concat([
|
||||||
AddressService.PREFIXES.OUTPUTS,
|
AddressService.PREFIXES.OUTPUTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN,
|
AddressService.SPACER_MIN,
|
||||||
heightBuffer,
|
heightBuffer,
|
||||||
txidBuffer,
|
txidBuffer,
|
||||||
@ -583,6 +618,7 @@ AddressService.prototype._decodeOutputKey = function(buffer) {
|
|||||||
var reader = new BufferReader(buffer);
|
var reader = new BufferReader(buffer);
|
||||||
var prefix = reader.read(1);
|
var prefix = reader.read(1);
|
||||||
var hashBuffer = reader.read(20);
|
var hashBuffer = reader.read(20);
|
||||||
|
var hashTypeBuffer = reader.read(1);
|
||||||
var spacer = reader.read(1);
|
var spacer = reader.read(1);
|
||||||
var height = reader.readUInt32BE();
|
var height = reader.readUInt32BE();
|
||||||
var txid = reader.read(32);
|
var txid = reader.read(32);
|
||||||
@ -590,6 +626,7 @@ AddressService.prototype._decodeOutputKey = function(buffer) {
|
|||||||
return {
|
return {
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
hashBuffer: hashBuffer,
|
hashBuffer: hashBuffer,
|
||||||
|
hashTypeBuffer: hashTypeBuffer,
|
||||||
height: height,
|
height: height,
|
||||||
txid: txid,
|
txid: txid,
|
||||||
outputIndex: outputIndex
|
outputIndex: outputIndex
|
||||||
@ -611,7 +648,7 @@ AddressService.prototype._decodeOutputValue = function(buffer) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._encodeInputKey = function(hashBuffer, height, prevTxIdBuffer, outputIndex) {
|
AddressService.prototype._encodeInputKey = function(hashBuffer, hashTypeBuffer, height, prevTxIdBuffer, outputIndex) {
|
||||||
var heightBuffer = new Buffer(4);
|
var heightBuffer = new Buffer(4);
|
||||||
heightBuffer.writeUInt32BE(height);
|
heightBuffer.writeUInt32BE(height);
|
||||||
var outputIndexBuffer = new Buffer(4);
|
var outputIndexBuffer = new Buffer(4);
|
||||||
@ -619,6 +656,7 @@ AddressService.prototype._encodeInputKey = function(hashBuffer, height, prevTxId
|
|||||||
return Buffer.concat([
|
return Buffer.concat([
|
||||||
AddressService.PREFIXES.SPENTS,
|
AddressService.PREFIXES.SPENTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN,
|
AddressService.SPACER_MIN,
|
||||||
heightBuffer,
|
heightBuffer,
|
||||||
prevTxIdBuffer,
|
prevTxIdBuffer,
|
||||||
@ -630,6 +668,7 @@ AddressService.prototype._decodeInputKey = function(buffer) {
|
|||||||
var reader = new BufferReader(buffer);
|
var reader = new BufferReader(buffer);
|
||||||
var prefix = reader.read(1);
|
var prefix = reader.read(1);
|
||||||
var hashBuffer = reader.read(20);
|
var hashBuffer = reader.read(20);
|
||||||
|
var hashTypeBuffer = reader.read(1);
|
||||||
var spacer = reader.read(1);
|
var spacer = reader.read(1);
|
||||||
var height = reader.readUInt32BE();
|
var height = reader.readUInt32BE();
|
||||||
var prevTxId = reader.read(32);
|
var prevTxId = reader.read(32);
|
||||||
@ -637,6 +676,7 @@ AddressService.prototype._decodeInputKey = function(buffer) {
|
|||||||
return {
|
return {
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
hashBuffer: hashBuffer,
|
hashBuffer: hashBuffer,
|
||||||
|
hashTypeBuffer: hashTypeBuffer,
|
||||||
height: height,
|
height: height,
|
||||||
prevTxId: prevTxId,
|
prevTxId: prevTxId,
|
||||||
outputIndex: outputIndex
|
outputIndex: outputIndex
|
||||||
@ -698,6 +738,17 @@ AddressService.prototype._decodeInputValueMap = function(buffer) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddressService.prototype._getAddressInfo = function(addressStr) {
|
||||||
|
var addrObj = bitcore.Address(addressStr);
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES_MAP[addrObj.type];
|
||||||
|
|
||||||
|
return {
|
||||||
|
hashBuffer: addrObj.hashBuffer,
|
||||||
|
hashTypeBuffer: hashTypeBuffer,
|
||||||
|
hashTypeReadable: addrObj.type
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is responsible for emitting events to any subscribers to the
|
* This function is responsible for emitting events to any subscribers to the
|
||||||
* `address/transaction` event.
|
* `address/transaction` event.
|
||||||
@ -902,6 +953,7 @@ AddressService.prototype.getInputForOutput = function(txid, outputIndex, options
|
|||||||
/**
|
/**
|
||||||
* Will give inputs that spend previous outputs for an address as an object with:
|
* Will give inputs that spend previous outputs for an address as an object with:
|
||||||
* address - The base58check encoded address
|
* address - The base58check encoded address
|
||||||
|
* hashType - The type of the address, e.g. 'pubkeyhash' or 'scripthash'
|
||||||
* txid - A string of the transaction hash
|
* txid - A string of the transaction hash
|
||||||
* outputIndex - A number of corresponding transaction input
|
* outputIndex - A number of corresponding transaction input
|
||||||
* height - The height of the block the transaction was included, will be -1 for mempool transactions
|
* height - The height of the block the transaction was included, will be -1 for mempool transactions
|
||||||
@ -921,7 +973,12 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) {
|
|||||||
var inputs = [];
|
var inputs = [];
|
||||||
var stream;
|
var stream;
|
||||||
|
|
||||||
var hashBuffer = bitcore.Address(addressStr).hashBuffer;
|
var addrObj = this._getAddressInfo(addressStr);
|
||||||
|
var hashBuffer = addrObj.hashBuffer;
|
||||||
|
var hashTypeBuffer = addrObj.hashTypeBuffer;
|
||||||
|
if (!hashTypeBuffer) {
|
||||||
|
return callback(new Error('Unknown address type: ' + addrObj.hashTypeReadable + ' for address: ' + addressStr));
|
||||||
|
}
|
||||||
|
|
||||||
if (options.start && options.end) {
|
if (options.start && options.end) {
|
||||||
|
|
||||||
@ -935,12 +992,14 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) {
|
|||||||
gte: Buffer.concat([
|
gte: Buffer.concat([
|
||||||
AddressService.PREFIXES.SPENTS,
|
AddressService.PREFIXES.SPENTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN,
|
AddressService.SPACER_MIN,
|
||||||
endBuffer
|
endBuffer
|
||||||
]),
|
]),
|
||||||
lte: Buffer.concat([
|
lte: Buffer.concat([
|
||||||
AddressService.PREFIXES.SPENTS,
|
AddressService.PREFIXES.SPENTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN,
|
AddressService.SPACER_MIN,
|
||||||
startBuffer
|
startBuffer
|
||||||
]),
|
]),
|
||||||
@ -948,7 +1007,7 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) {
|
|||||||
keyEncoding: 'binary'
|
keyEncoding: 'binary'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var allKey = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer]);
|
var allKey = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, hashTypeBuffer]);
|
||||||
stream = this.node.services.db.store.createReadStream({
|
stream = this.node.services.db.store.createReadStream({
|
||||||
gte: Buffer.concat([allKey, AddressService.SPACER_MIN]),
|
gte: Buffer.concat([allKey, AddressService.SPACER_MIN]),
|
||||||
lte: Buffer.concat([allKey, AddressService.SPACER_MAX]),
|
lte: Buffer.concat([allKey, AddressService.SPACER_MAX]),
|
||||||
@ -964,6 +1023,7 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) {
|
|||||||
|
|
||||||
var input = {
|
var input = {
|
||||||
address: addressStr,
|
address: addressStr,
|
||||||
|
hashType: addrObj.hashTypeReadable,
|
||||||
txid: value.txid.toString('hex'),
|
txid: value.txid.toString('hex'),
|
||||||
inputIndex: value.inputIndex,
|
inputIndex: value.inputIndex,
|
||||||
height: key.height,
|
height: key.height,
|
||||||
@ -988,7 +1048,7 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(options.queryMempool) {
|
if(options.queryMempool) {
|
||||||
self._getInputsMempool(addressStr, hashBuffer, function(err, mempoolInputs) {
|
self._getInputsMempool(addressStr, hashBuffer, hashTypeBuffer, function(err, mempoolInputs) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@ -1005,7 +1065,7 @@ AddressService.prototype.getInputs = function(addressStr, options, callback) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._getInputsMempool = function(addressStr, hashBuffer, callback) {
|
AddressService.prototype._getInputsMempool = function(addressStr, hashBuffer, hashTypeBuffer, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var mempoolInputs = [];
|
var mempoolInputs = [];
|
||||||
|
|
||||||
@ -1013,11 +1073,13 @@ AddressService.prototype._getInputsMempool = function(addressStr, hashBuffer, ca
|
|||||||
gte: Buffer.concat([
|
gte: Buffer.concat([
|
||||||
AddressService.MEMPREFIXES.SPENTS,
|
AddressService.MEMPREFIXES.SPENTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN
|
AddressService.SPACER_MIN
|
||||||
]),
|
]),
|
||||||
lte: Buffer.concat([
|
lte: Buffer.concat([
|
||||||
AddressService.MEMPREFIXES.SPENTS,
|
AddressService.MEMPREFIXES.SPENTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MAX
|
AddressService.SPACER_MAX
|
||||||
]),
|
]),
|
||||||
valueEncoding: 'binary',
|
valueEncoding: 'binary',
|
||||||
@ -1029,6 +1091,7 @@ AddressService.prototype._getInputsMempool = function(addressStr, hashBuffer, ca
|
|||||||
var inputIndex = data.value.readUInt32BE(32);
|
var inputIndex = data.value.readUInt32BE(32);
|
||||||
var output = {
|
var output = {
|
||||||
address: addressStr,
|
address: addressStr,
|
||||||
|
hashType: AddressService.HASH_TYPES_READABLE[hashTypeBuffer.toString('hex')],
|
||||||
txid: txid.toString('hex'), //TODO use a buffer
|
txid: txid.toString('hex'), //TODO use a buffer
|
||||||
inputIndex: inputIndex,
|
inputIndex: inputIndex,
|
||||||
height: -1,
|
height: -1,
|
||||||
@ -1082,6 +1145,7 @@ AddressService.prototype._getSpentMempool = function(txidBuffer, outputIndex, ca
|
|||||||
/**
|
/**
|
||||||
* Will give outputs for an address as an object with:
|
* Will give outputs for an address as an object with:
|
||||||
* address - The base58check encoded address
|
* address - The base58check encoded address
|
||||||
|
* hashType - The type of the address, e.g. 'pubkeyhash' or 'scripthash'
|
||||||
* txid - A string of the transaction hash
|
* txid - A string of the transaction hash
|
||||||
* outputIndex - A number of corresponding transaction output
|
* outputIndex - A number of corresponding transaction output
|
||||||
* height - The height of the block the transaction was included, will be -1 for mempool transactions
|
* height - The height of the block the transaction was included, will be -1 for mempool transactions
|
||||||
@ -1101,7 +1165,12 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) {
|
|||||||
$.checkArgument(_.isObject(options), 'Second argument is expected to be an options object.');
|
$.checkArgument(_.isObject(options), 'Second argument is expected to be an options object.');
|
||||||
$.checkArgument(_.isFunction(callback), 'Third argument is expected to be a callback function.');
|
$.checkArgument(_.isFunction(callback), 'Third argument is expected to be a callback function.');
|
||||||
|
|
||||||
var hashBuffer = bitcore.Address(addressStr).hashBuffer;
|
var addrObj = this._getAddressInfo(addressStr);
|
||||||
|
var hashBuffer = addrObj.hashBuffer;
|
||||||
|
var hashTypeBuffer = addrObj.hashTypeBuffer;
|
||||||
|
if (!hashTypeBuffer) {
|
||||||
|
return callback(new Error('Unknown address type: ' + addrObj.hashTypeReadable + ' for address: ' + addressStr));
|
||||||
|
}
|
||||||
|
|
||||||
var outputs = [];
|
var outputs = [];
|
||||||
var stream;
|
var stream;
|
||||||
@ -1117,12 +1186,14 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) {
|
|||||||
gte: Buffer.concat([
|
gte: Buffer.concat([
|
||||||
AddressService.PREFIXES.OUTPUTS,
|
AddressService.PREFIXES.OUTPUTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN,
|
AddressService.SPACER_MIN,
|
||||||
endBuffer
|
endBuffer
|
||||||
]),
|
]),
|
||||||
lte: Buffer.concat([
|
lte: Buffer.concat([
|
||||||
AddressService.PREFIXES.OUTPUTS,
|
AddressService.PREFIXES.OUTPUTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN,
|
AddressService.SPACER_MIN,
|
||||||
startBuffer
|
startBuffer
|
||||||
]),
|
]),
|
||||||
@ -1130,7 +1201,7 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) {
|
|||||||
keyEncoding: 'binary'
|
keyEncoding: 'binary'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var allKey = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer]);
|
var allKey = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer]);
|
||||||
stream = this.node.services.db.store.createReadStream({
|
stream = this.node.services.db.store.createReadStream({
|
||||||
gte: Buffer.concat([allKey, AddressService.SPACER_MIN]),
|
gte: Buffer.concat([allKey, AddressService.SPACER_MIN]),
|
||||||
lte: Buffer.concat([allKey, AddressService.SPACER_MAX]),
|
lte: Buffer.concat([allKey, AddressService.SPACER_MAX]),
|
||||||
@ -1146,6 +1217,7 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) {
|
|||||||
|
|
||||||
var output = {
|
var output = {
|
||||||
address: addressStr,
|
address: addressStr,
|
||||||
|
hashType: addrObj.hashTypeReadable,
|
||||||
txid: key.txid.toString('hex'), //TODO use a buffer
|
txid: key.txid.toString('hex'), //TODO use a buffer
|
||||||
outputIndex: key.outputIndex,
|
outputIndex: key.outputIndex,
|
||||||
height: key.height,
|
height: key.height,
|
||||||
@ -1172,7 +1244,7 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(options.queryMempool) {
|
if(options.queryMempool) {
|
||||||
self._getOutputsMempool(addressStr, hashBuffer, function(err, mempoolOutputs) {
|
self._getOutputsMempool(addressStr, hashBuffer, hashTypeBuffer, function(err, mempoolOutputs) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@ -1188,7 +1260,7 @@ AddressService.prototype.getOutputs = function(addressStr, options, callback) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._getOutputsMempool = function(addressStr, hashBuffer, callback) {
|
AddressService.prototype._getOutputsMempool = function(addressStr, hashBuffer, hashTypeBuffer, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var mempoolOutputs = [];
|
var mempoolOutputs = [];
|
||||||
|
|
||||||
@ -1196,11 +1268,13 @@ AddressService.prototype._getOutputsMempool = function(addressStr, hashBuffer, c
|
|||||||
gte: Buffer.concat([
|
gte: Buffer.concat([
|
||||||
AddressService.MEMPREFIXES.OUTPUTS,
|
AddressService.MEMPREFIXES.OUTPUTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MIN
|
AddressService.SPACER_MIN
|
||||||
]),
|
]),
|
||||||
lte: Buffer.concat([
|
lte: Buffer.concat([
|
||||||
AddressService.MEMPREFIXES.OUTPUTS,
|
AddressService.MEMPREFIXES.OUTPUTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
AddressService.SPACER_MAX
|
AddressService.SPACER_MAX
|
||||||
]),
|
]),
|
||||||
valueEncoding: 'binary',
|
valueEncoding: 'binary',
|
||||||
@ -1208,12 +1282,13 @@ AddressService.prototype._getOutputsMempool = function(addressStr, hashBuffer, c
|
|||||||
});
|
});
|
||||||
|
|
||||||
stream.on('data', function(data) {
|
stream.on('data', function(data) {
|
||||||
// Format of data: prefix: 1, hashBuffer: 20, txid: 32, outputIndex: 4
|
// Format of data: prefix: 1, hashBuffer: 20, hashTypeBuffer: 1, txid: 32, outputIndex: 4
|
||||||
var txid = data.key.slice(21, 53);
|
var txid = data.key.slice(22, 54);
|
||||||
var outputIndex = data.key.readUInt32BE(53);
|
var outputIndex = data.key.readUInt32BE(54);
|
||||||
var value = self._decodeOutputValue(data.value);
|
var value = self._decodeOutputValue(data.value);
|
||||||
var output = {
|
var output = {
|
||||||
address: addressStr,
|
address: addressStr,
|
||||||
|
hashType: AddressService.HASH_TYPES_READABLE[hashTypeBuffer.toString('hex')],
|
||||||
txid: txid.toString('hex'), //TODO use a buffer
|
txid: txid.toString('hex'), //TODO use a buffer
|
||||||
outputIndex: outputIndex,
|
outputIndex: outputIndex,
|
||||||
height: -1,
|
height: -1,
|
||||||
|
|||||||
@ -343,7 +343,9 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
am.node.network = Networks.livenet;
|
am.node.network = Networks.livenet;
|
||||||
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
|
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
|
||||||
var hashHex = bitcore.Address(address).hashBuffer.toString('hex');
|
var addrObj = bitcore.Address(address);
|
||||||
|
var hashHex = addrObj.hashBuffer.toString('hex');
|
||||||
|
var hashType = addrObj.type;
|
||||||
var messages = {};
|
var messages = {};
|
||||||
am.transactionOutputHandler(messages, tx, 0, true);
|
am.transactionOutputHandler(messages, tx, 0, true);
|
||||||
should.exist(messages[hashHex]);
|
should.exist(messages[hashHex]);
|
||||||
@ -351,6 +353,7 @@ describe('Address Service', function() {
|
|||||||
message.tx.should.equal(tx);
|
message.tx.should.equal(tx);
|
||||||
message.outputIndexes.should.deep.equal([0]);
|
message.outputIndexes.should.deep.equal([0]);
|
||||||
message.addressInfo.hashBuffer.toString('hex').should.equal(hashHex);
|
message.addressInfo.hashBuffer.toString('hex').should.equal(hashHex);
|
||||||
|
message.addressInfo.addressType.should.equal(hashType);
|
||||||
message.addressInfo.hashHex.should.equal(hashHex);
|
message.addressInfo.hashHex.should.equal(hashHex);
|
||||||
message.rejected.should.equal(true);
|
message.rejected.should.equal(true);
|
||||||
});
|
});
|
||||||
@ -446,16 +449,16 @@ describe('Address Service', function() {
|
|||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
operations.length.should.equal(151);
|
operations.length.should.equal(151);
|
||||||
operations[0].type.should.equal('put');
|
operations[0].type.should.equal('put');
|
||||||
operations[0].key.toString('hex').should.equal('0202a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b00000543abfdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e1692300000000');
|
operations[0].key.toString('hex').should.equal('0202a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b0100000543abfdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e1692300000000');
|
||||||
operations[0].value.toString('hex').should.equal('41e2a49ec1c0000076a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac');
|
operations[0].value.toString('hex').should.equal('41e2a49ec1c0000076a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac');
|
||||||
operations[3].type.should.equal('put');
|
operations[3].type.should.equal('put');
|
||||||
operations[3].key.toString('hex').should.equal('03fdbd324b28ea69e49c998816407dc055fb81d06e00000543ab3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020');
|
operations[3].key.toString('hex').should.equal('03fdbd324b28ea69e49c998816407dc055fb81d06e0100000543ab3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020');
|
||||||
operations[3].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000');
|
operations[3].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000');
|
||||||
operations[4].type.should.equal('put');
|
operations[4].type.should.equal('put');
|
||||||
operations[4].key.toString('hex').should.equal('053d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020');
|
operations[4].key.toString('hex').should.equal('053d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020');
|
||||||
operations[4].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000');
|
operations[4].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000');
|
||||||
operations[121].type.should.equal('put');
|
operations[121].type.should.equal('put');
|
||||||
operations[121].key.toString('hex').should.equal('029780ccd5356e2acc0ee439ee04e0fe69426c752800000543abe66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d00000001');
|
operations[121].key.toString('hex').should.equal('029780ccd5356e2acc0ee439ee04e0fe69426c75280100000543abe66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d00000001');
|
||||||
operations[121].value.toString('hex').should.equal('4147a6b00000000076a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac');
|
operations[121].value.toString('hex').should.equal('4147a6b00000000076a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -472,13 +475,13 @@ describe('Address Service', function() {
|
|||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
operations.length.should.equal(151);
|
operations.length.should.equal(151);
|
||||||
operations[0].type.should.equal('del');
|
operations[0].type.should.equal('del');
|
||||||
operations[0].key.toString('hex').should.equal('0202a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b00000543abfdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e1692300000000');
|
operations[0].key.toString('hex').should.equal('0202a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b0100000543abfdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e1692300000000');
|
||||||
operations[0].value.toString('hex').should.equal('41e2a49ec1c0000076a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac');
|
operations[0].value.toString('hex').should.equal('41e2a49ec1c0000076a91402a61d2066d19e9e2fd348a8320b7ebd4dd3ca2b88ac');
|
||||||
operations[3].type.should.equal('del');
|
operations[3].type.should.equal('del');
|
||||||
operations[3].key.toString('hex').should.equal('03fdbd324b28ea69e49c998816407dc055fb81d06e00000543ab3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020');
|
operations[3].key.toString('hex').should.equal('03fdbd324b28ea69e49c998816407dc055fb81d06e0100000543ab3d7d5d98df753ef2a4f82438513c509e3b11f3e738e94a7234967b03a03123a900000020');
|
||||||
operations[3].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000');
|
operations[3].value.toString('hex').should.equal('5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca00000000');
|
||||||
operations[121].type.should.equal('del');
|
operations[121].type.should.equal('del');
|
||||||
operations[121].key.toString('hex').should.equal('029780ccd5356e2acc0ee439ee04e0fe69426c752800000543abe66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d00000001');
|
operations[121].key.toString('hex').should.equal('029780ccd5356e2acc0ee439ee04e0fe69426c75280100000543abe66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d00000001');
|
||||||
operations[121].value.toString('hex').should.equal('4147a6b00000000076a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac');
|
operations[121].value.toString('hex').should.equal('4147a6b00000000076a9149780ccd5356e2acc0ee439ee04e0fe69426c752888ac');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -818,6 +821,7 @@ describe('Address Service', function() {
|
|||||||
var am;
|
var am;
|
||||||
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||||
var hashBuffer = bitcore.Address(address).hashBuffer;
|
var hashBuffer = bitcore.Address(address).hashBuffer;
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES.PUBKEY;
|
||||||
var db = {
|
var db = {
|
||||||
tip: {
|
tip: {
|
||||||
__height: 1
|
__height: 1
|
||||||
@ -866,8 +870,9 @@ describe('Address Service', function() {
|
|||||||
end: 12,
|
end: 12,
|
||||||
queryMempool: true
|
queryMempool: true
|
||||||
};
|
};
|
||||||
am._getInputsMempool = sinon.stub().callsArgWith(2, null, {
|
am._getInputsMempool = sinon.stub().callsArgWith(3, null, {
|
||||||
address: address,
|
address: address,
|
||||||
|
hashType: 'pubkeyhash',
|
||||||
height: -1,
|
height: -1,
|
||||||
confirmations: 0
|
confirmations: 0
|
||||||
});
|
});
|
||||||
@ -890,9 +895,11 @@ describe('Address Service', function() {
|
|||||||
var createReadStreamCallCount = 0;
|
var createReadStreamCallCount = 0;
|
||||||
am.node.services.db.store = {
|
am.node.services.db.store = {
|
||||||
createReadStream: function(ops) {
|
createReadStream: function(ops) {
|
||||||
var gte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('000000000c', 'hex')]);
|
var gte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer,
|
||||||
|
hashTypeBuffer, new Buffer('000000000c', 'hex')]);
|
||||||
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
||||||
var lte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('0000000010', 'hex')]);
|
var lte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer,
|
||||||
|
hashTypeBuffer, new Buffer('0000000010', 'hex')]);
|
||||||
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
||||||
createReadStreamCallCount++;
|
createReadStreamCallCount++;
|
||||||
return testStream;
|
return testStream;
|
||||||
@ -901,7 +908,7 @@ describe('Address Service', function() {
|
|||||||
am.node.services.bitcoind = {
|
am.node.services.bitcoind = {
|
||||||
getMempoolInputs: sinon.stub().returns([])
|
getMempoolInputs: sinon.stub().returns([])
|
||||||
};
|
};
|
||||||
am._getInputsMempool = sinon.stub().callsArgWith(2, null, []);
|
am._getInputsMempool = sinon.stub().callsArgWith(3, null, []);
|
||||||
am.getInputs(address, args, function(err, inputs) {
|
am.getInputs(address, args, function(err, inputs) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
inputs.length.should.equal(1);
|
inputs.length.should.equal(1);
|
||||||
@ -913,7 +920,7 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
createReadStreamCallCount.should.equal(1);
|
createReadStreamCallCount.should.equal(1);
|
||||||
var data = {
|
var data = {
|
||||||
key: new Buffer('33038a213afdfc551fc658e9a2a58a86e98d69b687000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
key: new Buffer('33038a213afdfc551fc658e9a2a58a86e98d69b68701000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
||||||
value: new Buffer('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000000', 'hex')
|
value: new Buffer('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000000', 'hex')
|
||||||
};
|
};
|
||||||
testStream.emit('data', data);
|
testStream.emit('data', data);
|
||||||
@ -927,9 +934,9 @@ describe('Address Service', function() {
|
|||||||
var createReadStreamCallCount = 0;
|
var createReadStreamCallCount = 0;
|
||||||
am.node.services.db.store = {
|
am.node.services.db.store = {
|
||||||
createReadStream: function(ops) {
|
createReadStream: function(ops) {
|
||||||
var gte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('00', 'hex')]);
|
var gte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, hashTypeBuffer, new Buffer('00', 'hex')]);
|
||||||
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
||||||
var lte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, new Buffer('ff', 'hex')]);
|
var lte = Buffer.concat([AddressService.PREFIXES.SPENTS, hashBuffer, hashTypeBuffer, new Buffer('ff', 'hex')]);
|
||||||
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
||||||
createReadStreamCallCount++;
|
createReadStreamCallCount++;
|
||||||
return testStream;
|
return testStream;
|
||||||
@ -949,7 +956,7 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
createReadStreamCallCount.should.equal(1);
|
createReadStreamCallCount.should.equal(1);
|
||||||
var data = {
|
var data = {
|
||||||
key: new Buffer('33038a213afdfc551fc658e9a2a58a86e98d69b687000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
key: new Buffer('33038a213afdfc551fc658e9a2a58a86e98d69b68701000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
||||||
value: new Buffer('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000000', 'hex')
|
value: new Buffer('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000000', 'hex')
|
||||||
};
|
};
|
||||||
testStream.emit('data', data);
|
testStream.emit('data', data);
|
||||||
@ -979,6 +986,7 @@ describe('Address Service', function() {
|
|||||||
var am;
|
var am;
|
||||||
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||||
var hashBuffer = bitcore.Address(address).hashBuffer;
|
var hashBuffer = bitcore.Address(address).hashBuffer;
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES.PUBKEY;
|
||||||
var db = {
|
var db = {
|
||||||
tip: {
|
tip: {
|
||||||
__height: 1
|
__height: 1
|
||||||
@ -1005,7 +1013,7 @@ describe('Address Service', function() {
|
|||||||
am.mempoolIndex = {};
|
am.mempoolIndex = {};
|
||||||
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
||||||
|
|
||||||
am._getInputsMempool(address, hashBuffer, function(err, outputs) {
|
am._getInputsMempool(address, hashBuffer, hashTypeBuffer, function(err, outputs) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.equal('readstreamerror');
|
err.message.should.equal('readstreamerror');
|
||||||
done();
|
done();
|
||||||
@ -1021,11 +1029,13 @@ describe('Address Service', function() {
|
|||||||
am.mempoolIndex = {};
|
am.mempoolIndex = {};
|
||||||
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
||||||
|
|
||||||
am._getInputsMempool(address, hashBuffer, function(err, outputs) {
|
am._getInputsMempool(address, hashBuffer, hashTypeBuffer, function(err, outputs) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
outputs.length.should.equal(1);
|
outputs.length.should.equal(1);
|
||||||
outputs[0].address.should.equal(address);
|
outputs[0].address.should.equal(address);
|
||||||
outputs[0].txid.should.equal(txid);
|
outputs[0].txid.should.equal(txid);
|
||||||
|
outputs[0].hashType.should.equal('pubkeyhash');
|
||||||
|
outputs[0].hashType.should.equal(AddressService.HASH_TYPES_READABLE[hashTypeBuffer.toString('hex')]);
|
||||||
outputs[0].inputIndex.should.equal(5);
|
outputs[0].inputIndex.should.equal(5);
|
||||||
outputs[0].height.should.equal(-1);
|
outputs[0].height.should.equal(-1);
|
||||||
outputs[0].confirmations.should.equal(0);
|
outputs[0].confirmations.should.equal(0);
|
||||||
@ -1099,6 +1109,7 @@ describe('Address Service', function() {
|
|||||||
var am;
|
var am;
|
||||||
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||||
var hashBuffer = bitcore.Address('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W').hashBuffer;
|
var hashBuffer = bitcore.Address('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W').hashBuffer;
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES.PUBKEY;
|
||||||
var db = {
|
var db = {
|
||||||
tip: {
|
tip: {
|
||||||
__height: 1
|
__height: 1
|
||||||
@ -1135,20 +1146,22 @@ describe('Address Service', function() {
|
|||||||
var createReadStreamCallCount = 0;
|
var createReadStreamCallCount = 0;
|
||||||
am.node.services.db.store = {
|
am.node.services.db.store = {
|
||||||
createReadStream: function(ops) {
|
createReadStream: function(ops) {
|
||||||
var gte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, new Buffer('000000000c', 'hex')]);
|
var gte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer, new Buffer('000000000c', 'hex')]);
|
||||||
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
||||||
var lte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, new Buffer('0000000010', 'hex')]);
|
var lte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer, new Buffer('0000000010', 'hex')]);
|
||||||
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
||||||
createReadStreamCallCount++;
|
createReadStreamCallCount++;
|
||||||
return testStream;
|
return testStream;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
am._getOutputsMempool = sinon.stub().callsArgWith(2, null, []);
|
am._getOutputsMempool = sinon.stub().callsArgWith(3, null, []);
|
||||||
am.getOutputs(address, args, function(err, outputs) {
|
am.getOutputs(address, args, function(err, outputs) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
outputs.length.should.equal(1);
|
outputs.length.should.equal(1);
|
||||||
outputs[0].address.should.equal(address);
|
outputs[0].address.should.equal(address);
|
||||||
outputs[0].txid.should.equal('125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87');
|
outputs[0].txid.should.equal('125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87');
|
||||||
|
outputs[0].hashType.should.equal('pubkeyhash');
|
||||||
|
outputs[0].hashType.should.equal(AddressService.HASH_TYPES_READABLE[hashTypeBuffer.toString('hex')]);
|
||||||
outputs[0].outputIndex.should.equal(1);
|
outputs[0].outputIndex.should.equal(1);
|
||||||
outputs[0].satoshis.should.equal(4527773864);
|
outputs[0].satoshis.should.equal(4527773864);
|
||||||
outputs[0].script.should.equal('76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac');
|
outputs[0].script.should.equal('76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac');
|
||||||
@ -1157,7 +1170,7 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
createReadStreamCallCount.should.equal(1);
|
createReadStreamCallCount.should.equal(1);
|
||||||
var data = {
|
var data = {
|
||||||
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b687000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b68701000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
||||||
value: new Buffer('41f0de058a80000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex')
|
value: new Buffer('41f0de058a80000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex')
|
||||||
};
|
};
|
||||||
testStream.emit('data', data);
|
testStream.emit('data', data);
|
||||||
@ -1170,10 +1183,11 @@ describe('Address Service', function() {
|
|||||||
createReadStream: sinon.stub().returns(readStream1)
|
createReadStream: sinon.stub().returns(readStream1)
|
||||||
};
|
};
|
||||||
|
|
||||||
am._getOutputsMempool = sinon.stub().callsArgWith(2, null, [
|
am._getOutputsMempool = sinon.stub().callsArgWith(3, null, [
|
||||||
{
|
{
|
||||||
address: address,
|
address: address,
|
||||||
height: -1,
|
height: -1,
|
||||||
|
hashType: 'pubkeyhash',
|
||||||
confirmations: 0,
|
confirmations: 0,
|
||||||
txid: 'aa2db23f670596e96ed94c405fd11848c8f236d266ee96da37ecd919e53b4371',
|
txid: 'aa2db23f670596e96ed94c405fd11848c8f236d266ee96da37ecd919e53b4371',
|
||||||
satoshis: 307627737,
|
satoshis: 307627737,
|
||||||
@ -1186,18 +1200,21 @@ describe('Address Service', function() {
|
|||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
outputs.length.should.equal(3);
|
outputs.length.should.equal(3);
|
||||||
outputs[0].address.should.equal(address);
|
outputs[0].address.should.equal(address);
|
||||||
|
outputs[0].hashType.should.equal('pubkeyhash');
|
||||||
outputs[0].txid.should.equal('125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87');
|
outputs[0].txid.should.equal('125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87');
|
||||||
outputs[0].outputIndex.should.equal(1);
|
outputs[0].outputIndex.should.equal(1);
|
||||||
outputs[0].satoshis.should.equal(4527773864);
|
outputs[0].satoshis.should.equal(4527773864);
|
||||||
outputs[0].script.should.equal('76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac');
|
outputs[0].script.should.equal('76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac');
|
||||||
outputs[0].height.should.equal(345000);
|
outputs[0].height.should.equal(345000);
|
||||||
outputs[1].address.should.equal(address);
|
outputs[1].address.should.equal(address);
|
||||||
|
outputs[1].hashType.should.equal('pubkeyhash');
|
||||||
outputs[1].txid.should.equal('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae7');
|
outputs[1].txid.should.equal('3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae7');
|
||||||
outputs[1].outputIndex.should.equal(2);
|
outputs[1].outputIndex.should.equal(2);
|
||||||
outputs[1].satoshis.should.equal(10000);
|
outputs[1].satoshis.should.equal(10000);
|
||||||
outputs[1].script.should.equal('76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac');
|
outputs[1].script.should.equal('76a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac');
|
||||||
outputs[1].height.should.equal(345004);
|
outputs[1].height.should.equal(345004);
|
||||||
outputs[2].address.should.equal(address);
|
outputs[2].address.should.equal(address);
|
||||||
|
outputs[2].hashType.should.equal('pubkeyhash');
|
||||||
outputs[2].txid.should.equal('aa2db23f670596e96ed94c405fd11848c8f236d266ee96da37ecd919e53b4371');
|
outputs[2].txid.should.equal('aa2db23f670596e96ed94c405fd11848c8f236d266ee96da37ecd919e53b4371');
|
||||||
outputs[2].script.should.equal('76a914f6db95c81dea3d10f0ff8d890927751bf7b203c188ac');
|
outputs[2].script.should.equal('76a914f6db95c81dea3d10f0ff8d890927751bf7b203c188ac');
|
||||||
outputs[2].height.should.equal(-1);
|
outputs[2].height.should.equal(-1);
|
||||||
@ -1206,12 +1223,12 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var data1 = {
|
var data1 = {
|
||||||
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b68700000543a8125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b6870100000543a8125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
||||||
value: new Buffer('41f0de058a80000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex')
|
value: new Buffer('41f0de058a80000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex')
|
||||||
};
|
};
|
||||||
|
|
||||||
var data2 = {
|
var data2 = {
|
||||||
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b68700000543ac3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000002', 'hex'),
|
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b6870100000543ac3b6bc2939d1a70ce04bc4f619ee32608fbff5e565c1f9b02e4eaa97959c59ae700000002', 'hex'),
|
||||||
value: new Buffer('40c388000000000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex')
|
value: new Buffer('40c388000000000076a914038a213afdfc551fc658e9a2a58a86e98d69b68788ac', 'hex')
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1237,12 +1254,98 @@ describe('Address Service', function() {
|
|||||||
readStream2.emit('close');
|
readStream2.emit('close');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should print outputs for a p2sh address', function(done) {
|
||||||
|
// This address has the redeemScript 0x038a213afdfc551fc658e9a2a58a86e98d69b687,
|
||||||
|
// which is the same as the pkhash for the address 1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W.
|
||||||
|
// See https://github.com/bitpay/bitcore-node/issues/377
|
||||||
|
var address = '321jRYeWBrLBWr2j1KYnAFGico3GUdd5q7';
|
||||||
|
var hashBuffer = bitcore.Address(address).hashBuffer;
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES.REDEEMSCRIPT;
|
||||||
|
var testStream = new EventEmitter();
|
||||||
|
var args = {
|
||||||
|
start: 15,
|
||||||
|
end: 12,
|
||||||
|
queryMempool: true
|
||||||
|
};
|
||||||
|
var createReadStreamCallCount = 0;
|
||||||
|
am.node.services.db.store = {
|
||||||
|
createReadStream: function(ops) {
|
||||||
|
var gte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer, new Buffer('000000000c', 'hex')]);
|
||||||
|
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
||||||
|
var lte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer, new Buffer('0000000010', 'hex')]);
|
||||||
|
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
||||||
|
createReadStreamCallCount++;
|
||||||
|
return testStream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
am._getOutputsMempool = sinon.stub().callsArgWith(3, null, []);
|
||||||
|
am.getOutputs(address, args, function(err, outputs) {
|
||||||
|
should.not.exist(err);
|
||||||
|
outputs.length.should.equal(1);
|
||||||
|
outputs[0].address.should.equal(address);
|
||||||
|
outputs[0].txid.should.equal('125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf87');
|
||||||
|
outputs[0].hashType.should.equal('scripthash');
|
||||||
|
outputs[0].hashType.should.equal(AddressService.HASH_TYPES_READABLE[hashTypeBuffer.toString('hex')]);
|
||||||
|
outputs[0].outputIndex.should.equal(1);
|
||||||
|
outputs[0].satoshis.should.equal(4527773864);
|
||||||
|
outputs[0].script.should.equal('a914038a213afdfc551fc658e9a2a58a86e98d69b68787');
|
||||||
|
outputs[0].height.should.equal(15);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
createReadStreamCallCount.should.equal(1);
|
||||||
|
var data = {
|
||||||
|
// note '68702', '02' meaning p2sh redeemScript, not p2pkh
|
||||||
|
// value is also the p2sh script, not p2pkh
|
||||||
|
key: new Buffer('02038a213afdfc551fc658e9a2a58a86e98d69b68702000000000f125dd0e50fc732d67c37b6c56be7f9dc00b6859cebf982ee2cc83ed2d604bf8700000001', 'hex'),
|
||||||
|
value: new Buffer('41f0de058a800000a914038a213afdfc551fc658e9a2a58a86e98d69b68787', 'hex')
|
||||||
|
};
|
||||||
|
testStream.emit('data', data);
|
||||||
|
testStream.emit('close');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not print outputs for a p2pkh address, if the output was sent to a p2sh redeemScript', function(done) {
|
||||||
|
// This address has the redeemScript 0x038a213afdfc551fc658e9a2a58a86e98d69b687,
|
||||||
|
// which is the same as the pkhash for the address 1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W.
|
||||||
|
// See https://github.com/bitpay/bitcore-node/issues/377
|
||||||
|
var address = '321jRYeWBrLBWr2j1KYnAFGico3GUdd5q7';
|
||||||
|
var hashBuffer = bitcore.Address(address).hashBuffer;
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES.REDEEMSCRIPT;
|
||||||
|
var testStream = new EventEmitter();
|
||||||
|
var args = {
|
||||||
|
start: 15,
|
||||||
|
end: 12,
|
||||||
|
queryMempool: true
|
||||||
|
};
|
||||||
|
var createReadStreamCallCount = 0;
|
||||||
|
|
||||||
|
// Verifying that the db query is looking for a redeemScript, *not* a p2pkh
|
||||||
|
am.node.services.db.store = {
|
||||||
|
createReadStream: function(ops) {
|
||||||
|
var gte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer, new Buffer('000000000c', 'hex')]);
|
||||||
|
ops.gte.toString('hex').should.equal(gte.toString('hex'));
|
||||||
|
var lte = Buffer.concat([AddressService.PREFIXES.OUTPUTS, hashBuffer, hashTypeBuffer, new Buffer('0000000010', 'hex')]);
|
||||||
|
ops.lte.toString('hex').should.equal(lte.toString('hex'));
|
||||||
|
createReadStreamCallCount++;
|
||||||
|
return testStream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
am._getOutputsMempool = sinon.stub().callsArgWith(3, null, []);
|
||||||
|
am.getOutputs(address, args, function(err, outputs) {
|
||||||
|
should.not.exist(err);
|
||||||
|
outputs.length.should.equal(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
createReadStreamCallCount.should.equal(1);
|
||||||
|
testStream.emit('close');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#_getOutputsMempool', function() {
|
describe('#_getOutputsMempool', function() {
|
||||||
var am;
|
var am;
|
||||||
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||||
var hashBuffer = bitcore.Address(address).hashBuffer;
|
var hashBuffer = bitcore.Address(address).hashBuffer;
|
||||||
|
var hashTypeBuffer = AddressService.HASH_TYPES.PUBKEY;
|
||||||
var db = {
|
var db = {
|
||||||
tip: {
|
tip: {
|
||||||
__height: 1
|
__height: 1
|
||||||
@ -1268,7 +1371,7 @@ describe('Address Service', function() {
|
|||||||
var testStream = new EventEmitter();
|
var testStream = new EventEmitter();
|
||||||
am.mempoolIndex = {};
|
am.mempoolIndex = {};
|
||||||
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
||||||
am._getOutputsMempool(address, hashBuffer, function(err, outputs) {
|
am._getOutputsMempool(address, hashBuffer, hashTypeBuffer, function(err, outputs) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.equal('readstreamerror');
|
err.message.should.equal('readstreamerror');
|
||||||
done();
|
done();
|
||||||
@ -1283,12 +1386,13 @@ describe('Address Service', function() {
|
|||||||
am.mempoolIndex = {};
|
am.mempoolIndex = {};
|
||||||
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
||||||
|
|
||||||
am._getOutputsMempool(address, hashBuffer, function(err, outputs) {
|
am._getOutputsMempool(address, hashBuffer, hashTypeBuffer, function(err, outputs) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
outputs.length.should.equal(1);
|
outputs.length.should.equal(1);
|
||||||
outputs[0].address.should.equal(address);
|
outputs[0].address.should.equal(address);
|
||||||
|
outputs[0].hashType.should.equal('pubkeyhash');
|
||||||
outputs[0].txid.should.equal(txid);
|
outputs[0].txid.should.equal(txid);
|
||||||
outputs[0].outputIndex.should.equal(outputIndex);
|
outputs[0].outputIndex.should.equal(outputIndex);
|
||||||
outputs[0].height.should.equal(-1);
|
outputs[0].height.should.equal(-1);
|
||||||
@ -1304,8 +1408,9 @@ describe('Address Service', function() {
|
|||||||
var outputIndexBuffer = new Buffer(4);
|
var outputIndexBuffer = new Buffer(4);
|
||||||
outputIndexBuffer.writeUInt32BE(outputIndex);
|
outputIndexBuffer.writeUInt32BE(outputIndex);
|
||||||
var keyData = Buffer.concat([
|
var keyData = Buffer.concat([
|
||||||
new Buffer('01', 'hex'),
|
AddressService.MEMPREFIXES.OUTPUTS,
|
||||||
hashBuffer,
|
hashBuffer,
|
||||||
|
hashTypeBuffer,
|
||||||
txidBuffer,
|
txidBuffer,
|
||||||
outputIndexBuffer
|
outputIndexBuffer
|
||||||
]);
|
]);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user