bitcoind: add getDetailedTransaction method
Adds a new method getDetailedTransaction with a standard JavaScript object with block information, address, amounts and fees. And removes the getTransactionWithBlockInfo method since this new method is equivalent, and will serialize over an API correctly. Also includes a new method getBlockOverview to get the txids for a block, that can be combined with getDetailedTransaction for viewing block transactions with additional information.
This commit is contained in:
parent
950a9d521c
commit
8bddf4f0d6
@ -113,7 +113,8 @@ Bitcoin.prototype._initCaches = function() {
|
|||||||
this.txidsCache = LRU(50000);
|
this.txidsCache = LRU(50000);
|
||||||
this.balanceCache = LRU(50000);
|
this.balanceCache = LRU(50000);
|
||||||
this.summaryCache = LRU(50000);
|
this.summaryCache = LRU(50000);
|
||||||
this.transactionInfoCache = LRU(100000);
|
this.blockOverviewCache = LRU(144);
|
||||||
|
this.transactionDetailedCache = LRU(100000);
|
||||||
|
|
||||||
// caches valid indefinitely
|
// caches valid indefinitely
|
||||||
this.transactionCache = LRU(100000);
|
this.transactionCache = LRU(100000);
|
||||||
@ -150,6 +151,7 @@ Bitcoin.prototype.getAPIMethods = function() {
|
|||||||
['getBlock', this, this.getBlock, 1],
|
['getBlock', this, this.getBlock, 1],
|
||||||
['getRawBlock', this, this.getRawBlock, 1],
|
['getRawBlock', this, this.getRawBlock, 1],
|
||||||
['getBlockHeader', this, this.getBlockHeader, 1],
|
['getBlockHeader', this, this.getBlockHeader, 1],
|
||||||
|
['getBlockOverview', this, this.getBlockOverview, 1],
|
||||||
['getBlockHashesByTimestamp', this, this.getBlockHashesByTimestamp, 2],
|
['getBlockHashesByTimestamp', this, this.getBlockHashesByTimestamp, 2],
|
||||||
['getBestBlockHash', this, this.getBestBlockHash, 0],
|
['getBestBlockHash', this, this.getBestBlockHash, 0],
|
||||||
['getSpentInfo', this, this.getSpentInfo, 1],
|
['getSpentInfo', this, this.getSpentInfo, 1],
|
||||||
@ -157,8 +159,8 @@ Bitcoin.prototype.getAPIMethods = function() {
|
|||||||
['syncPercentage', this, this.syncPercentage, 0],
|
['syncPercentage', this, this.syncPercentage, 0],
|
||||||
['isSynced', this, this.isSynced, 0],
|
['isSynced', this, this.isSynced, 0],
|
||||||
['getRawTransaction', this, this.getRawTransaction, 1],
|
['getRawTransaction', this, this.getRawTransaction, 1],
|
||||||
['getTransaction', this, this.getTransaction, 2],
|
['getTransaction', this, this.getTransaction, 1],
|
||||||
['getTransactionWithBlockInfo', this, this.getTransactionWithBlockInfo, 2],
|
['getDetailedTransaction', this, this.getDetailedTransaction, 1],
|
||||||
['sendTransaction', this, this.sendTransaction, 1],
|
['sendTransaction', this, this.sendTransaction, 1],
|
||||||
['estimateFee', this, this.estimateFee, 1],
|
['estimateFee', this, this.estimateFee, 1],
|
||||||
['getAddressTxids', this, this.getAddressTxids, 2],
|
['getAddressTxids', this, this.getAddressTxids, 2],
|
||||||
@ -320,11 +322,12 @@ Bitcoin.prototype._checkConfigIndexes = function(spawnConfig, node) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._resetCaches = function() {
|
Bitcoin.prototype._resetCaches = function() {
|
||||||
this.transactionInfoCache.reset();
|
this.transactionDetailedCache.reset();
|
||||||
this.utxosCache.reset();
|
this.utxosCache.reset();
|
||||||
this.txidsCache.reset();
|
this.txidsCache.reset();
|
||||||
this.balanceCache.reset();
|
this.balanceCache.reset();
|
||||||
this.summaryCache.reset();
|
this.summaryCache.reset();
|
||||||
|
this.blockOverviewCache.reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._tryAll = function(func, callback) {
|
Bitcoin.prototype._tryAll = function(func, callback) {
|
||||||
@ -1096,8 +1099,8 @@ Bitcoin.prototype.getAddressTxids = function(addressArg, options, callback) {
|
|||||||
Bitcoin.prototype._getConfirmationsDetail = function(transaction) {
|
Bitcoin.prototype._getConfirmationsDetail = function(transaction) {
|
||||||
$.checkState(this.height > 0, 'current height is unknown');
|
$.checkState(this.height > 0, 'current height is unknown');
|
||||||
var confirmations = 0;
|
var confirmations = 0;
|
||||||
if (transaction.__height >= 0) {
|
if (transaction.height >= 0) {
|
||||||
confirmations = this.height - transaction.__height + 1;
|
confirmations = this.height - transaction.height + 1;
|
||||||
}
|
}
|
||||||
if (confirmations < 0) {
|
if (confirmations < 0) {
|
||||||
log.warn('Negative confirmations calculated for transaction:', transaction.hash);
|
log.warn('Negative confirmations calculated for transaction:', transaction.hash);
|
||||||
@ -1106,44 +1109,38 @@ Bitcoin.prototype._getConfirmationsDetail = function(transaction) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._getAddressDetailsForInput = function(input, inputIndex, result, addressStrings) {
|
Bitcoin.prototype._getAddressDetailsForInput = function(input, inputIndex, result, addressStrings) {
|
||||||
if (!input.script) {
|
if (!input.address) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var inputAddress = input.script.toAddress(this.node.network);
|
var address = input.address;
|
||||||
if (inputAddress) {
|
if (addressStrings.indexOf(address) >= 0) {
|
||||||
var inputAddressString = inputAddress.toString();
|
if (!result.addresses[address]) {
|
||||||
if (addressStrings.indexOf(inputAddressString) >= 0) {
|
result.addresses[address] = {
|
||||||
if (!result.addresses[inputAddressString]) {
|
inputIndexes: [inputIndex],
|
||||||
result.addresses[inputAddressString] = {
|
outputIndexes: []
|
||||||
inputIndexes: [inputIndex],
|
};
|
||||||
outputIndexes: []
|
} else {
|
||||||
};
|
result.addresses[address].inputIndexes.push(inputIndex);
|
||||||
} else {
|
|
||||||
result.addresses[inputAddressString].inputIndexes.push(inputIndex);
|
|
||||||
}
|
|
||||||
result.satoshis -= input.output.satoshis;
|
|
||||||
}
|
}
|
||||||
|
result.satoshis -= input.satoshis;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._getAddressDetailsForOutput = function(output, outputIndex, result, addressStrings) {
|
Bitcoin.prototype._getAddressDetailsForOutput = function(output, outputIndex, result, addressStrings) {
|
||||||
if (!output.script) {
|
if (!output.address) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var outputAddress = output.script.toAddress(this.node.network);
|
var address = output.address;
|
||||||
if (outputAddress) {
|
if (addressStrings.indexOf(address) >= 0) {
|
||||||
var outputAddressString = outputAddress.toString();
|
if (!result.addresses[address]) {
|
||||||
if (addressStrings.indexOf(outputAddressString) >= 0) {
|
result.addresses[address] = {
|
||||||
if (!result.addresses[outputAddressString]) {
|
inputIndexes: [],
|
||||||
result.addresses[outputAddressString] = {
|
outputIndexes: [outputIndex]
|
||||||
inputIndexes: [],
|
};
|
||||||
outputIndexes: [outputIndex]
|
} else {
|
||||||
};
|
result.addresses[address].outputIndexes.push(outputIndex);
|
||||||
} else {
|
|
||||||
result.addresses[outputAddressString].outputIndexes.push(outputIndex);
|
|
||||||
}
|
|
||||||
result.satoshis += output.satoshis;
|
|
||||||
}
|
}
|
||||||
|
result.satoshis += output.satoshis;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1163,6 +1160,8 @@ Bitcoin.prototype._getAddressDetailsForTransaction = function(transaction, addre
|
|||||||
this._getAddressDetailsForOutput(output, outputIndex, result, addressStrings);
|
this._getAddressDetailsForOutput(output, outputIndex, result, addressStrings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$.checkState(Number.isFinite(result.satoshis));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1171,35 +1170,25 @@ Bitcoin.prototype._getAddressDetailsForTransaction = function(transaction, addre
|
|||||||
* @param {Object} txid - A bitcoin transaction id
|
* @param {Object} txid - A bitcoin transaction id
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
Bitcoin.prototype._getDetailedTransaction = function(txid, options, next) {
|
Bitcoin.prototype._getAddressDetailedTransaction = function(txid, options, next) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.getTransactionWithBlockInfo(
|
self.getDetailedTransaction(
|
||||||
txid,
|
txid,
|
||||||
function(err, transaction) {
|
function(err, transaction) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.populateInputs(self, [], function(err) {
|
var addressDetails = self._getAddressDetailsForTransaction(transaction, options.addressStrings);
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
var addressDetails = self._getAddressDetailsForTransaction(transaction, options.addressStrings);
|
var details = {
|
||||||
|
addresses: addressDetails.addresses,
|
||||||
var details = {
|
satoshis: addressDetails.satoshis,
|
||||||
addresses: addressDetails.addresses,
|
confirmations: self._getConfirmationsDetail(transaction),
|
||||||
satoshis: addressDetails.satoshis,
|
tx: transaction
|
||||||
height: transaction.__height,
|
};
|
||||||
confirmations: self._getConfirmationsDetail(transaction),
|
next(null, details);
|
||||||
timestamp: transaction.__timestamp,
|
|
||||||
// TODO bitcore-lib should return null instead of throwing error on coinbase
|
|
||||||
fees: !transaction.isCoinbase() ? transaction.getFee() : null,
|
|
||||||
tx: transaction
|
|
||||||
};
|
|
||||||
next(null, details);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -1270,7 +1259,7 @@ Bitcoin.prototype.getAddressHistory = function(addressArg, options, callback) {
|
|||||||
async.mapSeries(
|
async.mapSeries(
|
||||||
txids,
|
txids,
|
||||||
function(txid, next) {
|
function(txid, next) {
|
||||||
self._getDetailedTransaction(txid, {
|
self._getAddressDetailedTransaction(txid, {
|
||||||
queryMempool: queryMempool,
|
queryMempool: queryMempool,
|
||||||
addressStrings: addressStrings
|
addressStrings: addressStrings
|
||||||
}, next);
|
}, next);
|
||||||
@ -1437,6 +1426,69 @@ Bitcoin.prototype.getRawBlock = function(blockArg, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to getBlockHeader but will include a list of txids
|
||||||
|
* @param {String|Number} block - A block hash or block height number
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
Bitcoin.prototype.getBlockOverview = function(blockArg, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function queryBlock(blockhash) {
|
||||||
|
var cachedBlock = self.blockOverviewCache.get(blockhash);
|
||||||
|
if (cachedBlock) {
|
||||||
|
return setImmediate(function() {
|
||||||
|
callback(null, cachedBlock);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self._tryAll(function(done) {
|
||||||
|
self.client.getBlock(blockhash, true, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
return done(self._wrapRPCError(err));
|
||||||
|
}
|
||||||
|
var result = response.result;
|
||||||
|
var blockOverview = {
|
||||||
|
hash: result.hash,
|
||||||
|
version: result.version,
|
||||||
|
confirmations: result.confirmations,
|
||||||
|
height: result.height,
|
||||||
|
chainWork: result.chainwork,
|
||||||
|
prevHash: result.previousblockhash,
|
||||||
|
nextHash: result.nextblockhash,
|
||||||
|
merkleRoot: result.merkleroot,
|
||||||
|
time: result.time,
|
||||||
|
medianTime: result.mediantime,
|
||||||
|
nonce: result.nonce,
|
||||||
|
bits: result.bits,
|
||||||
|
difficulty: result.difficulty,
|
||||||
|
txids: result.tx
|
||||||
|
};
|
||||||
|
self.blockOverviewCache.set(blockhash, blockOverview);
|
||||||
|
done(null, blockOverview);
|
||||||
|
});
|
||||||
|
}, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isNumber(blockArg)) {
|
||||||
|
self._tryAll(function(done) {
|
||||||
|
self.client.getBlockHash(blockArg, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
return done(self._wrapRPCError(err));
|
||||||
|
}
|
||||||
|
done(null, response.result);
|
||||||
|
});
|
||||||
|
}, function(err, blockhash) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
queryBlock(blockhash);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
queryBlock(blockArg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will retrieve a block as a Bitcore object
|
* Will retrieve a block as a Bitcore object
|
||||||
* @param {String|Number} block - A block hash or block height number
|
* @param {String|Number} block - A block hash or block height number
|
||||||
@ -1672,19 +1724,101 @@ Bitcoin.prototype.getTransaction = function(txid, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will get a transaction as Bitcore Transaction with additional fields:
|
* Will get a detailed view of a transaction including addresses, amounts and fees.
|
||||||
|
*
|
||||||
|
* Example result:
|
||||||
* {
|
* {
|
||||||
* __blockHash: '2725743288feae6bdaa976590af7cb12d7b535b5a242787de6d2789c73682ed1',
|
* blockHash: '000000000000000002cd0ba6e8fae058747d2344929ed857a18d3484156c9250',
|
||||||
* __height: 48,
|
* height: 411462,
|
||||||
* __timestamp: 1442951110, // in seconds
|
* blockTimestamp: 1463070382,
|
||||||
* }
|
* version: 1,
|
||||||
* @param {String} txid - The transaction hash
|
* hash: 'de184cc227f6d1dc0316c7484aa68b58186a18f89d853bb2428b02040c394479',
|
||||||
|
* locktime: 411451,
|
||||||
|
* coinbase: true,
|
||||||
|
* inputs: [
|
||||||
|
* {
|
||||||
|
* prevTxId: '3d003413c13eec3fa8ea1fe8bbff6f40718c66facffe2544d7516c9e2900cac2',
|
||||||
|
* outputIndex: 0,
|
||||||
|
* sequence: 123456789,
|
||||||
|
* script: [hexString],
|
||||||
|
* scriptAsm: [asmString],
|
||||||
|
* satoshis: 771146
|
||||||
|
* }
|
||||||
|
* ],
|
||||||
|
* outputs: [
|
||||||
|
* {
|
||||||
|
* satoshis: 811146,
|
||||||
|
* script: '76a914d2955017f4e3d6510c57b427cf45ae29c372c99088ac',
|
||||||
|
* scriptAsm: 'OP_DUP OP_HASH160 d2955017f4e3d6510c57b427cf45ae29c372c990 OP_EQUALVERIFY OP_CHECKSIG',
|
||||||
|
* address: '1LCTmj15p7sSXv3jmrPfA6KGs6iuepBiiG',
|
||||||
|
* spentTxId: '4316b98e7504073acd19308b4b8c9f4eeb5e811455c54c0ebfe276c0b1eb6315',
|
||||||
|
* spentIndex: 1,
|
||||||
|
* spentHeight: 100
|
||||||
|
* }
|
||||||
|
* ],
|
||||||
|
* inputSatoshis: 771146,
|
||||||
|
* outputSatoshis: 811146,
|
||||||
|
* feeSatoshis: 40000
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @param {String} txid - The hex string of the transaction
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
Bitcoin.prototype.getTransactionWithBlockInfo = function(txid, callback) {
|
Bitcoin.prototype.getDetailedTransaction = function(txid, callback) {
|
||||||
// TODO give response back as standard js object with bitcore tx
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var tx = self.transactionInfoCache.get(txid);
|
var tx = self.transactionDetailedCache.get(txid);
|
||||||
|
|
||||||
|
function addInputsToTx(tx, result) {
|
||||||
|
tx.inputs = [];
|
||||||
|
tx.inputSatoshis = 0;
|
||||||
|
for(var inputIndex = 0; inputIndex < result.vin.length; inputIndex++) {
|
||||||
|
var input = result.vin[inputIndex];
|
||||||
|
if (!tx.coinbase) {
|
||||||
|
tx.inputSatoshis += input.valueSat;
|
||||||
|
}
|
||||||
|
var script;
|
||||||
|
var scriptAsm;
|
||||||
|
if (input.scriptSig) {
|
||||||
|
script = input.scriptSig.hex;
|
||||||
|
scriptAsm = input.scriptSig.asm;
|
||||||
|
} else if (input.coinbase) {
|
||||||
|
script = input.coinbase;
|
||||||
|
scriptAsm = null;
|
||||||
|
}
|
||||||
|
tx.inputs.push({
|
||||||
|
prevTxId: input.txid || null,
|
||||||
|
outputIndex: _.isUndefined(input.vout) ? null : input.vout,
|
||||||
|
script: script,
|
||||||
|
scriptAsm: scriptAsm || null,
|
||||||
|
sequence: input.sequence,
|
||||||
|
address: input.address || null,
|
||||||
|
satoshis: _.isUndefined(input.valueSat) ? null : input.valueSat
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addOutputsToTx(tx, result) {
|
||||||
|
tx.outputs = [];
|
||||||
|
tx.outputSatoshis = 0;
|
||||||
|
for(var outputIndex = 0; outputIndex < result.vout.length; outputIndex++) {
|
||||||
|
var out = result.vout[outputIndex];
|
||||||
|
tx.outputSatoshis += out.valueSat;
|
||||||
|
var address = null;
|
||||||
|
if (out.scriptPubKey && out.scriptPubKey.addresses && out.scriptPubKey.addresses.length > 0) {
|
||||||
|
address = out.scriptPubKey.addresses[0];
|
||||||
|
}
|
||||||
|
tx.outputs.push({
|
||||||
|
satoshis: out.valueSat,
|
||||||
|
script: out.scriptPubKey.hex,
|
||||||
|
scriptAsm: out.scriptPubKey.asm,
|
||||||
|
spentTxId: out.spentTxId,
|
||||||
|
spentIndex: out.spentIndex,
|
||||||
|
spentHeight: out.spentHeight,
|
||||||
|
address: address
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
return setImmediate(function() {
|
return setImmediate(function() {
|
||||||
callback(null, tx);
|
callback(null, tx);
|
||||||
@ -1695,18 +1829,32 @@ Bitcoin.prototype.getTransactionWithBlockInfo = function(txid, callback) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return done(self._wrapRPCError(err));
|
return done(self._wrapRPCError(err));
|
||||||
}
|
}
|
||||||
var tx = Transaction();
|
var result = response.result;
|
||||||
tx.fromString(response.result.hex);
|
var tx = {
|
||||||
tx.__blockHash = response.result.blockhash;
|
hex: result.hex,
|
||||||
tx.__height = response.result.height ? response.result.height : -1;
|
blockHash: result.blockhash,
|
||||||
tx.__timestamp = response.result.time;
|
height: result.height ? result.height : -1,
|
||||||
|
blockTimestamp: result.time,
|
||||||
|
version: result.version,
|
||||||
|
hash: txid,
|
||||||
|
locktime: result.locktime,
|
||||||
|
};
|
||||||
|
|
||||||
for (var i = 0; i < response.result.vout.length; i++) {
|
if (result.vin[0] && result.vin[0].coinbase) {
|
||||||
tx.outputs[i].__spentTxId = response.result.vout[i].spentTxId;
|
tx.coinbase = true;
|
||||||
tx.outputs[i].__spentIndex = response.result.vout[i].spentIndex;
|
|
||||||
tx.outputs[i].__spentHeight = response.result.vout[i].spentHeight;
|
|
||||||
}
|
}
|
||||||
self.transactionInfoCache.set(txid, tx);
|
|
||||||
|
addInputsToTx(tx, result);
|
||||||
|
addOutputsToTx(tx, result);
|
||||||
|
|
||||||
|
if (!tx.coinbase) {
|
||||||
|
tx.feeSatoshis = tx.inputSatoshis - tx.outputSatoshis;
|
||||||
|
} else {
|
||||||
|
tx.feeSatoshis = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.transactionDetailedCache.set(txid, tx);
|
||||||
|
|
||||||
done(null, tx);
|
done(null, tx);
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
|
|||||||
@ -424,16 +424,38 @@ describe('Bitcoind Functionality', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('get transaction with block info', function() {
|
describe('get detailed transaction', function() {
|
||||||
it('should include tx with height and timestamp', function(done) {
|
it('should include details for coinbase tx', function(done) {
|
||||||
bitcoind.getTransactionWithBlockInfo(utxos[0].txid, function(err, tx) {
|
bitcoind.getDetailedTransaction(utxos[0].txid, function(err, tx) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
should.exist(tx.__height);
|
should.exist(tx.height);
|
||||||
tx.__height.should.be.a('number');
|
tx.height.should.be.a('number');
|
||||||
should.exist(tx.__timestamp);
|
should.exist(tx.blockTimestamp);
|
||||||
should.exist(tx.__blockHash);
|
should.exist(tx.blockHash);
|
||||||
|
tx.coinbase.should.equal(true);
|
||||||
|
tx.version.should.equal(1);
|
||||||
|
tx.hex.should.be.a('string');
|
||||||
|
tx.locktime.should.equal(0);
|
||||||
|
tx.feeSatoshis.should.equal(0);
|
||||||
|
tx.outputSatoshis.should.equal(50 * 1e8);
|
||||||
|
tx.inputSatoshis.should.equal(0);
|
||||||
|
tx.inputs.length.should.equal(1);
|
||||||
|
tx.outputs.length.should.equal(1);
|
||||||
|
should.equal(tx.inputs[0].prevTxId, null);
|
||||||
|
should.equal(tx.inputs[0].outputIndex, null);
|
||||||
|
tx.inputs[0].script.should.be.a('string');
|
||||||
|
should.equal(tx.inputs[0].scriptAsm, null);
|
||||||
|
should.equal(tx.inputs[0].address, null);
|
||||||
|
should.equal(tx.inputs[0].satoshis, null);
|
||||||
|
tx.outputs[0].satoshis.should.equal(50 * 1e8);
|
||||||
|
tx.outputs[0].script.should.be.a('string');
|
||||||
|
tx.outputs[0].scriptAsm.should.be.a('string');
|
||||||
|
tx.outputs[0].spentTxId.should.be.a('string');
|
||||||
|
tx.outputs[0].spentIndex.should.equal(0);
|
||||||
|
tx.outputs[0].spentHeight.should.be.a('number');
|
||||||
|
tx.outputs[0].address.should.be.a('string');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -205,9 +205,8 @@ describe('Node Functionality', function() {
|
|||||||
info.addresses[address].inputIndexes.should.deep.equal([]);
|
info.addresses[address].inputIndexes.should.deep.equal([]);
|
||||||
info.satoshis.should.equal(10 * 1e8);
|
info.satoshis.should.equal(10 * 1e8);
|
||||||
info.confirmations.should.equal(3);
|
info.confirmations.should.equal(3);
|
||||||
info.timestamp.should.be.a('number');
|
info.tx.blockTimestamp.should.be.a('number');
|
||||||
info.fees.should.be.within(950, 4000);
|
info.tx.feeSatoshis.should.be.within(950, 4000);
|
||||||
info.tx.should.be.an.instanceof(Transaction);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -395,13 +394,13 @@ describe('Node Functionality', function() {
|
|||||||
results.totalCount.should.equal(4);
|
results.totalCount.should.equal(4);
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(4);
|
history.length.should.equal(4);
|
||||||
history[0].height.should.equal(159);
|
history[0].tx.height.should.equal(159);
|
||||||
history[0].confirmations.should.equal(1);
|
history[0].confirmations.should.equal(1);
|
||||||
history[1].height.should.equal(158);
|
history[1].tx.height.should.equal(158);
|
||||||
should.exist(history[1].addresses[address4]);
|
should.exist(history[1].addresses[address4]);
|
||||||
history[2].height.should.equal(157);
|
history[2].tx.height.should.equal(157);
|
||||||
should.exist(history[2].addresses[address3]);
|
should.exist(history[2].addresses[address3]);
|
||||||
history[3].height.should.equal(156);
|
history[3].tx.height.should.equal(156);
|
||||||
should.exist(history[3].addresses[address2]);
|
should.exist(history[3].addresses[address2]);
|
||||||
history[3].satoshis.should.equal(tx2Amount);
|
history[3].satoshis.should.equal(tx2Amount);
|
||||||
history[3].tx.hash.should.equal(tx2Hash);
|
history[3].tx.hash.should.equal(tx2Hash);
|
||||||
@ -429,9 +428,9 @@ describe('Node Functionality', function() {
|
|||||||
results.totalCount.should.equal(2);
|
results.totalCount.should.equal(2);
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(2);
|
history.length.should.equal(2);
|
||||||
history[0].height.should.equal(158);
|
history[0].tx.height.should.equal(158);
|
||||||
history[0].confirmations.should.equal(2);
|
history[0].confirmations.should.equal(2);
|
||||||
history[1].height.should.equal(157);
|
history[1].tx.height.should.equal(157);
|
||||||
should.exist(history[1].addresses[address3]);
|
should.exist(history[1].addresses[address3]);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -456,8 +455,8 @@ describe('Node Functionality', function() {
|
|||||||
results.totalCount.should.equal(2);
|
results.totalCount.should.equal(2);
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(2);
|
history.length.should.equal(2);
|
||||||
history[0].height.should.equal(157);
|
history[0].tx.height.should.equal(157);
|
||||||
history[1].height.should.equal(156);
|
history[1].tx.height.should.equal(156);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -481,9 +480,9 @@ describe('Node Functionality', function() {
|
|||||||
results.totalCount.should.equal(4);
|
results.totalCount.should.equal(4);
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(3);
|
history.length.should.equal(3);
|
||||||
history[0].height.should.equal(159);
|
history[0].tx.height.should.equal(159);
|
||||||
history[0].confirmations.should.equal(1);
|
history[0].confirmations.should.equal(1);
|
||||||
history[1].height.should.equal(158);
|
history[1].tx.height.should.equal(158);
|
||||||
should.exist(history[1].addresses[address4]);
|
should.exist(history[1].addresses[address4]);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -501,18 +500,18 @@ describe('Node Functionality', function() {
|
|||||||
results.totalCount.should.equal(6);
|
results.totalCount.should.equal(6);
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(6);
|
history.length.should.equal(6);
|
||||||
history[0].height.should.equal(159);
|
history[0].tx.height.should.equal(159);
|
||||||
history[0].addresses[address].inputIndexes.should.deep.equal([0, 1]);
|
history[0].addresses[address].inputIndexes.should.deep.equal([0, 1]);
|
||||||
history[0].addresses[address].outputIndexes.should.deep.equal([2]);
|
history[0].addresses[address].outputIndexes.should.deep.equal([2]);
|
||||||
history[0].confirmations.should.equal(1);
|
history[0].confirmations.should.equal(1);
|
||||||
history[1].height.should.equal(158);
|
history[1].tx.height.should.equal(158);
|
||||||
history[2].height.should.equal(157);
|
history[2].tx.height.should.equal(157);
|
||||||
history[3].height.should.equal(156);
|
history[3].tx.height.should.equal(156);
|
||||||
history[4].height.should.equal(155);
|
history[4].tx.height.should.equal(155);
|
||||||
history[4].satoshis.should.equal(-10000);
|
history[4].satoshis.should.equal(-10000);
|
||||||
history[4].addresses[address].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]);
|
history[4].addresses[address].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]);
|
||||||
history[4].addresses[address].inputIndexes.should.deep.equal([0]);
|
history[4].addresses[address].inputIndexes.should.deep.equal([0]);
|
||||||
history[5].height.should.equal(152);
|
history[5].tx.height.should.equal(152);
|
||||||
history[5].satoshis.should.equal(10 * 1e8);
|
history[5].satoshis.should.equal(10 * 1e8);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -561,7 +560,7 @@ describe('Node Functionality', function() {
|
|||||||
}
|
}
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(1);
|
history.length.should.equal(1);
|
||||||
history[0].height.should.equal(159);
|
history[0].tx.height.should.equal(159);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -576,7 +575,7 @@ describe('Node Functionality', function() {
|
|||||||
}
|
}
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(1);
|
history.length.should.equal(1);
|
||||||
history[0].height.should.equal(158);
|
history[0].tx.height.should.equal(158);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -591,7 +590,7 @@ describe('Node Functionality', function() {
|
|||||||
}
|
}
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(1);
|
history.length.should.equal(1);
|
||||||
history[0].height.should.equal(157);
|
history[0].tx.height.should.equal(157);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -606,7 +605,7 @@ describe('Node Functionality', function() {
|
|||||||
}
|
}
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(1);
|
history.length.should.equal(1);
|
||||||
history[0].height.should.equal(156);
|
history[0].tx.height.should.equal(156);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -621,7 +620,7 @@ describe('Node Functionality', function() {
|
|||||||
}
|
}
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(1);
|
history.length.should.equal(1);
|
||||||
history[0].height.should.equal(155);
|
history[0].tx.height.should.equal(155);
|
||||||
history[0].satoshis.should.equal(-10000);
|
history[0].satoshis.should.equal(-10000);
|
||||||
history[0].addresses[address].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]);
|
history[0].addresses[address].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]);
|
||||||
history[0].addresses[address].inputIndexes.should.deep.equal([0]);
|
history[0].addresses[address].inputIndexes.should.deep.equal([0]);
|
||||||
@ -639,7 +638,7 @@ describe('Node Functionality', function() {
|
|||||||
}
|
}
|
||||||
var history = results.items;
|
var history = results.items;
|
||||||
history.length.should.equal(1);
|
history.length.should.equal(1);
|
||||||
history[0].height.should.equal(152);
|
history[0].tx.height.should.equal(152);
|
||||||
history[0].satoshis.should.equal(10 * 1e8);
|
history[0].satoshis.should.equal(10 * 1e8);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -744,13 +743,13 @@ describe('Node Functionality', function() {
|
|||||||
it('will not show confirmation count for orphaned transaction', function(done) {
|
it('will not show confirmation count for orphaned transaction', function(done) {
|
||||||
// This test verifies that in the situation that the transaction is not in the mempool and
|
// This test verifies that in the situation that the transaction is not in the mempool and
|
||||||
// is included in an orphaned block transaction index that the confirmation count will be unconfirmed.
|
// is included in an orphaned block transaction index that the confirmation count will be unconfirmed.
|
||||||
node.getTransactionWithBlockInfo(orphanedTransaction, function(err, data) {
|
node.getDetailedTransaction(orphanedTransaction, function(err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
should.exist(data);
|
should.exist(data);
|
||||||
should.exist(data.__height);
|
should.exist(data.height);
|
||||||
data.__height.should.equal(-1);
|
data.height.should.equal(-1);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,8 +6,8 @@ root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
|
|||||||
platform=`uname -a | awk '{print tolower($1)}'`
|
platform=`uname -a | awk '{print tolower($1)}'`
|
||||||
arch=`uname -m`
|
arch=`uname -m`
|
||||||
version="0.12.0"
|
version="0.12.0"
|
||||||
url="https://github.com/bitpay/bitcoin/releases/download"
|
url="https://github.com/braydonf/bitcoin/releases/download"
|
||||||
tag="v0.12-bitcore-rc1"
|
tag="v0.12-bitcore-rc2-spent"
|
||||||
|
|
||||||
if [ "${platform}" == "linux" ]; then
|
if [ "${platform}" == "linux" ]; then
|
||||||
if [ "${arch}" == "x86_64" ]; then
|
if [ "${arch}" == "x86_64" ]; then
|
||||||
|
|||||||
@ -5,6 +5,7 @@ var EventEmitter = require('events').EventEmitter;
|
|||||||
var should = require('chai').should();
|
var should = require('chai').should();
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var bitcore = require('bitcore-lib');
|
var bitcore = require('bitcore-lib');
|
||||||
|
var _ = bitcore.deps._;
|
||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
var proxyquire = require('proxyquire');
|
var proxyquire = require('proxyquire');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
@ -51,7 +52,7 @@ describe('Bitcoin Service', function() {
|
|||||||
should.exist(bitcoind.txidsCache);
|
should.exist(bitcoind.txidsCache);
|
||||||
should.exist(bitcoind.balanceCache);
|
should.exist(bitcoind.balanceCache);
|
||||||
should.exist(bitcoind.summaryCache);
|
should.exist(bitcoind.summaryCache);
|
||||||
should.exist(bitcoind.transactionInfoCache);
|
should.exist(bitcoind.transactionDetailedCache);
|
||||||
|
|
||||||
should.exist(bitcoind.transactionCache);
|
should.exist(bitcoind.transactionCache);
|
||||||
should.exist(bitcoind.rawTransactionCache);
|
should.exist(bitcoind.rawTransactionCache);
|
||||||
@ -90,7 +91,7 @@ describe('Bitcoin Service', function() {
|
|||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
var methods = bitcoind.getAPIMethods();
|
var methods = bitcoind.getAPIMethods();
|
||||||
should.exist(methods);
|
should.exist(methods);
|
||||||
methods.length.should.equal(20);
|
methods.length.should.equal(21);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -295,14 +296,14 @@ describe('Bitcoin Service', function() {
|
|||||||
var keys = [];
|
var keys = [];
|
||||||
for (var i = 0; i < 10; i++) {
|
for (var i = 0; i < 10; i++) {
|
||||||
keys.push(crypto.randomBytes(32));
|
keys.push(crypto.randomBytes(32));
|
||||||
bitcoind.transactionInfoCache.set(keys[i], {});
|
bitcoind.transactionDetailedCache.set(keys[i], {});
|
||||||
bitcoind.utxosCache.set(keys[i], {});
|
bitcoind.utxosCache.set(keys[i], {});
|
||||||
bitcoind.txidsCache.set(keys[i], {});
|
bitcoind.txidsCache.set(keys[i], {});
|
||||||
bitcoind.balanceCache.set(keys[i], {});
|
bitcoind.balanceCache.set(keys[i], {});
|
||||||
bitcoind.summaryCache.set(keys[i], {});
|
bitcoind.summaryCache.set(keys[i], {});
|
||||||
}
|
}
|
||||||
bitcoind._resetCaches();
|
bitcoind._resetCaches();
|
||||||
should.equal(bitcoind.transactionInfoCache.get(keys[0]), undefined);
|
should.equal(bitcoind.transactionDetailedCache.get(keys[0]), undefined);
|
||||||
should.equal(bitcoind.utxosCache.get(keys[0]), undefined);
|
should.equal(bitcoind.utxosCache.get(keys[0]), undefined);
|
||||||
should.equal(bitcoind.txidsCache.get(keys[0]), undefined);
|
should.equal(bitcoind.txidsCache.get(keys[0]), undefined);
|
||||||
should.equal(bitcoind.balanceCache.get(keys[0]), undefined);
|
should.equal(bitcoind.balanceCache.get(keys[0]), undefined);
|
||||||
@ -1919,7 +1920,7 @@ describe('Bitcoin Service', function() {
|
|||||||
});
|
});
|
||||||
it('should get 1 confirmation', function() {
|
it('should get 1 confirmation', function() {
|
||||||
var tx = new Transaction(txhex);
|
var tx = new Transaction(txhex);
|
||||||
tx.__height = 10;
|
tx.height = 10;
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
bitcoind.height = 10;
|
bitcoind.height = 10;
|
||||||
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
||||||
@ -1929,7 +1930,7 @@ describe('Bitcoin Service', function() {
|
|||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
var tx = new Transaction(txhex);
|
var tx = new Transaction(txhex);
|
||||||
bitcoind.height = 11;
|
bitcoind.height = 11;
|
||||||
tx.__height = 10;
|
tx.height = 10;
|
||||||
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
||||||
confirmations.should.equal(2);
|
confirmations.should.equal(2);
|
||||||
});
|
});
|
||||||
@ -1937,7 +1938,7 @@ describe('Bitcoin Service', function() {
|
|||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
var tx = new Transaction(txhex);
|
var tx = new Transaction(txhex);
|
||||||
bitcoind.height = 3;
|
bitcoind.height = 3;
|
||||||
tx.__height = 10;
|
tx.height = 10;
|
||||||
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
||||||
log.warn.callCount.should.equal(1);
|
log.warn.callCount.should.equal(1);
|
||||||
confirmations.should.equal(0);
|
confirmations.should.equal(0);
|
||||||
@ -1946,7 +1947,7 @@ describe('Bitcoin Service', function() {
|
|||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
var tx = new Transaction(txhex);
|
var tx = new Transaction(txhex);
|
||||||
bitcoind.height = 1000;
|
bitcoind.height = 1000;
|
||||||
tx.__height = 1;
|
tx.height = 1;
|
||||||
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
var confirmations = bitcoind._getConfirmationsDetail(tx);
|
||||||
confirmations.should.equal(1000);
|
confirmations.should.equal(1000);
|
||||||
});
|
});
|
||||||
@ -1955,46 +1956,37 @@ describe('Bitcoin Service', function() {
|
|||||||
describe('#_getAddressDetailsForTransaction', function() {
|
describe('#_getAddressDetailsForTransaction', function() {
|
||||||
it('will calculate details for the transaction', function(done) {
|
it('will calculate details for the transaction', function(done) {
|
||||||
/* jshint sub:true */
|
/* jshint sub:true */
|
||||||
var tx = bitcore.Transaction({
|
var tx = {
|
||||||
'hash': 'b12b3ae8489c5a566b629a3c62ce4c51c3870af550fb5dc77d715b669a91343c',
|
inputs: [
|
||||||
'version': 1,
|
|
||||||
'inputs': [
|
|
||||||
{
|
{
|
||||||
'prevTxId': 'a2b7ea824a92f4a4944686e67ec1001bc8785348b8c111c226f782084077b543',
|
satoshis: 1000000000,
|
||||||
'outputIndex': 0,
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'
|
||||||
'sequenceNumber': 4294967295,
|
|
||||||
'script': '47304402201b81c933297241960a57ae1b2952863b965ac8c9ec7466ff0b715712d27548d50220576e115b63864f003889443525f47c7cf0bc1e2b5108398da085b221f267ba2301210229766f1afa25ca499a51f8e01c292b0255a21a41bb6685564a1607a811ffe924',
|
|
||||||
'scriptString': '71 0x304402201b81c933297241960a57ae1b2952863b965ac8c9ec7466ff0b715712d27548d50220576e115b63864f003889443525f47c7cf0bc1e2b5108398da085b221f267ba2301 33 0x0229766f1afa25ca499a51f8e01c292b0255a21a41bb6685564a1607a811ffe924',
|
|
||||||
'output': {
|
|
||||||
'satoshis': 1000000000,
|
|
||||||
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'outputs': [
|
outputs: [
|
||||||
{
|
{
|
||||||
'satoshis': 100000000,
|
satoshis: 100000000,
|
||||||
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'satoshis': 200000000,
|
satoshis: 200000000,
|
||||||
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'satoshis': 50000000,
|
satoshis: 50000000,
|
||||||
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'satoshis': 300000000,
|
satoshis: 300000000,
|
||||||
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'satoshis': 349990000,
|
satoshis: 349990000,
|
||||||
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'nLockTime': 0
|
locktime: 0
|
||||||
});
|
};
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
var addresses = ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'];
|
var addresses = ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'];
|
||||||
var details = bitcoind._getAddressDetailsForTransaction(tx, addresses);
|
var details = bitcoind._getAddressDetailsForTransaction(tx, addresses);
|
||||||
@ -2008,105 +2000,40 @@ describe('Bitcoin Service', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#_getDetailedTransaction', function() {
|
describe('#_getAddressDetailedTransaction', function() {
|
||||||
it('will get detailed transaction info', function(done) {
|
it('will get detailed transaction info', function(done) {
|
||||||
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
||||||
var tx = {
|
var tx = {
|
||||||
populateInputs: sinon.stub().callsArg(2),
|
height: 20,
|
||||||
__height: 20,
|
|
||||||
__timestamp: 1453134151,
|
|
||||||
isCoinbase: sinon.stub().returns(false),
|
|
||||||
getFee: sinon.stub().returns(1000)
|
|
||||||
};
|
};
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
bitcoind.getTransactionWithBlockInfo = sinon.stub().callsArgWith(1, null, tx);
|
bitcoind.getDetailedTransaction = sinon.stub().callsArgWith(1, null, tx);
|
||||||
bitcoind.height = 300;
|
bitcoind.height = 300;
|
||||||
|
var addresses = {};
|
||||||
bitcoind._getAddressDetailsForTransaction = sinon.stub().returns({
|
bitcoind._getAddressDetailsForTransaction = sinon.stub().returns({
|
||||||
addresses: {},
|
addresses: addresses,
|
||||||
satoshis: 1000,
|
satoshis: 1000,
|
||||||
});
|
});
|
||||||
bitcoind._getDetailedTransaction(txid, {}, function(err) {
|
bitcoind._getAddressDetailedTransaction(txid, {}, function(err, details) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
details.addresses.should.equal(addresses);
|
||||||
|
details.satoshis.should.equal(1000);
|
||||||
|
details.confirmations.should.equal(281);
|
||||||
|
details.tx.should.equal(tx);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('give error from getTransactionWithBlockInfo', function(done) {
|
it('give error from getDetailedTransaction', function(done) {
|
||||||
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
bitcoind.getTransactionWithBlockInfo = sinon.stub().callsArgWith(1, new Error('test'));
|
bitcoind.getDetailedTransaction = sinon.stub().callsArgWith(1, new Error('test'));
|
||||||
bitcoind._getDetailedTransaction(txid, {}, function(err) {
|
bitcoind._getAddressDetailedTransaction(txid, {}, function(err) {
|
||||||
err.should.be.instanceof(Error);
|
err.should.be.instanceof(Error);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('give error from populateInputs', function(done) {
|
|
||||||
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
|
||||||
var tx = {
|
|
||||||
populateInputs: sinon.stub().callsArgWith(2, new Error('test')),
|
|
||||||
};
|
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
|
||||||
bitcoind.getTransactionWithBlockInfo = sinon.stub().callsArgWith(1, null, tx);
|
|
||||||
bitcoind._getDetailedTransaction(txid, {}, function(err) {
|
|
||||||
err.should.be.instanceof(Error);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('will correct detailed info', function(done) {
|
|
||||||
// block #314159
|
|
||||||
// txid 30169e8bf78bc27c4014a7aba3862c60e2e3cce19e52f1909c8255e4b7b3174e
|
|
||||||
// outputIndex 1
|
|
||||||
var txAddress = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo';
|
|
||||||
var txString = '0100000001a08ee59fcd5d86fa170abb6d925d62d5c5c476359681b70877c04f270c4ef246000000008a47304402203fb9b476bb0c37c9b9ed5784ebd67ae589492be11d4ae1612be29887e3e4ce750220741ef83781d1b3a5df8c66fa1957ad0398c733005310d7d9b1d8c2310ef4f74c0141046516ad02713e51ecf23ac9378f1069f9ae98e7de2f2edbf46b7836096e5dce95a05455cc87eaa1db64f39b0c63c0a23a3b8df1453dbd1c8317f967c65223cdf8ffffffff02b0a75fac000000001976a91484b45b9bf3add8f7a0f3daad305fdaf6b73441ea88ac20badc02000000001976a914809dc14496f99b6deb722cf46d89d22f4beb8efd88ac00000000';
|
|
||||||
var previousTxString = '010000000155532fad2869bb951b0bd646a546887f6ee668c4c0ee13bf3f1c4bce6d6e3ed9000000008c4930460221008540795f4ef79b1d2549c400c61155ca5abbf3089c84ad280e1ba6db2a31abce022100d7d162175483d51174d40bba722e721542c924202a0c2970b07e680b51f3a0670141046516ad02713e51ecf23ac9378f1069f9ae98e7de2f2edbf46b7836096e5dce95a05455cc87eaa1db64f39b0c63c0a23a3b8df1453dbd1c8317f967c65223cdf8ffffffff02f0af3caf000000001976a91484b45b9bf3add8f7a0f3daad305fdaf6b73441ea88ac80969800000000001976a91421277e65777760d1f3c7c982ba14ed8f934f005888ac00000000';
|
|
||||||
var transaction = new Transaction();
|
|
||||||
var previousTransaction = new Transaction();
|
|
||||||
previousTransaction.fromString(previousTxString);
|
|
||||||
var previousTransactionTxid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
|
||||||
transaction.fromString(txString);
|
|
||||||
var txid = transaction.hash;
|
|
||||||
transaction.__blockHash = '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45';
|
|
||||||
transaction.__height = 314159;
|
|
||||||
transaction.__timestamp = 1407292005;
|
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
|
||||||
bitcoind.height = 314159;
|
|
||||||
bitcoind.getTransactionWithBlockInfo = sinon.stub().callsArgWith(1, null, transaction);
|
|
||||||
bitcoind.getTransaction = function(prevTxid, callback) {
|
|
||||||
prevTxid.should.equal(previousTransactionTxid);
|
|
||||||
setImmediate(function() {
|
|
||||||
callback(null, previousTransaction);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var transactionInfo = {
|
|
||||||
addresses: {},
|
|
||||||
txid: txid,
|
|
||||||
timestamp: 1407292005,
|
|
||||||
satoshis: 48020000,
|
|
||||||
address: txAddress
|
|
||||||
};
|
|
||||||
transactionInfo.addresses[txAddress] = {};
|
|
||||||
transactionInfo.addresses[txAddress].outputIndexes = [1];
|
|
||||||
transactionInfo.addresses[txAddress].inputIndexes = [];
|
|
||||||
bitcoind._getAddressDetailsForTransaction = sinon.stub().returns(transactionInfo);
|
|
||||||
bitcoind._getDetailedTransaction(txid, {}, function(err, info) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
info.addresses[txAddress].should.deep.equal({
|
|
||||||
outputIndexes: [1],
|
|
||||||
inputIndexes: []
|
|
||||||
});
|
|
||||||
info.satoshis.should.equal(48020000);
|
|
||||||
info.height.should.equal(314159);
|
|
||||||
info.confirmations.should.equal(1);
|
|
||||||
info.timestamp.should.equal(1407292005);
|
|
||||||
info.fees.should.equal(20000);
|
|
||||||
info.tx.should.equal(transaction);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#_getAddressStrings', function() {
|
describe('#_getAddressStrings', function() {
|
||||||
@ -2221,7 +2148,7 @@ describe('Bitcoin Service', function() {
|
|||||||
});
|
});
|
||||||
it('will paginate', function(done) {
|
it('will paginate', function(done) {
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
bitcoind._getDetailedTransaction = function(txid, options, callback) {
|
bitcoind._getAddressDetailedTransaction = function(txid, options, callback) {
|
||||||
callback(null, txid);
|
callback(null, txid);
|
||||||
};
|
};
|
||||||
var txids = ['one', 'two', 'three', 'four'];
|
var txids = ['one', 'two', 'three', 'four'];
|
||||||
@ -3075,7 +3002,7 @@ describe('Bitcoin Service', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getTransactionWithBlockInfo', function() {
|
describe('#getDetailedTransaction', function() {
|
||||||
var txBuffer = new Buffer('01000000016f95980911e01c2c664b3e78299527a47933aac61a515930a8fe0213d1ac9abe01000000da0047304402200e71cda1f71e087c018759ba3427eb968a9ea0b1decd24147f91544629b17b4f0220555ee111ed0fc0f751ffebf097bdf40da0154466eb044e72b6b3dcd5f06807fa01483045022100c86d6c8b417bff6cc3bbf4854c16bba0aaca957e8f73e19f37216e2b06bb7bf802205a37be2f57a83a1b5a8cc511dc61466c11e9ba053c363302e7b99674be6a49fc0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9148a31d53a448c18996e81ce67811e5fb7da21e4468738c9d6f90000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000', 'hex');
|
var txBuffer = new Buffer('01000000016f95980911e01c2c664b3e78299527a47933aac61a515930a8fe0213d1ac9abe01000000da0047304402200e71cda1f71e087c018759ba3427eb968a9ea0b1decd24147f91544629b17b4f0220555ee111ed0fc0f751ffebf097bdf40da0154466eb044e72b6b3dcd5f06807fa01483045022100c86d6c8b417bff6cc3bbf4854c16bba0aaca957e8f73e19f37216e2b06bb7bf802205a37be2f57a83a1b5a8cc511dc61466c11e9ba053c363302e7b99674be6a49fc0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9148a31d53a448c18996e81ce67811e5fb7da21e4468738c9d6f90000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000', 'hex');
|
||||||
var info = {
|
var info = {
|
||||||
blockHash: '00000000000ec715852ea2ecae4dc8563f62d603c820f81ac284cd5be0a944d6',
|
blockHash: '00000000000ec715852ea2ecae4dc8563f62d603c820f81ac284cd5be0a944d6',
|
||||||
@ -3083,7 +3010,40 @@ describe('Bitcoin Service', function() {
|
|||||||
timestamp: 1439559434000,
|
timestamp: 1439559434000,
|
||||||
buffer: txBuffer
|
buffer: txBuffer
|
||||||
};
|
};
|
||||||
|
var rpcRawTransaction = {
|
||||||
|
hex: txBuffer.toString('hex'),
|
||||||
|
blockhash: info.blockHash,
|
||||||
|
height: info.height,
|
||||||
|
version: 1,
|
||||||
|
locktime: 411451,
|
||||||
|
time: info.timestamp,
|
||||||
|
vin: [
|
||||||
|
{
|
||||||
|
valueSat: 110,
|
||||||
|
address: 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW',
|
||||||
|
txid: '3d003413c13eec3fa8ea1fe8bbff6f40718c66facffe2544d7516c9e2900cac2',
|
||||||
|
sequence: 0xFFFFFFFF,
|
||||||
|
vout: 0,
|
||||||
|
scriptSig: {
|
||||||
|
hex: 'scriptSigHex',
|
||||||
|
asm: 'scriptSigAsm'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
vout: [
|
||||||
|
{
|
||||||
|
spentTxId: '4316b98e7504073acd19308b4b8c9f4eeb5e811455c54c0ebfe276c0b1eb6315',
|
||||||
|
spentIndex: 2,
|
||||||
|
spentHeight: 100,
|
||||||
|
valueSat: 100,
|
||||||
|
scriptPubKey: {
|
||||||
|
hex: '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac',
|
||||||
|
asm: 'OP_DUP OP_HASH160 0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc OP_EQUALVERIFY OP_CHECKSIG',
|
||||||
|
addresses: ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
it('should give a transaction with height and timestamp', function(done) {
|
it('should give a transaction with height and timestamp', function(done) {
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
bitcoind.nodes.push({
|
bitcoind.nodes.push({
|
||||||
@ -3092,39 +3052,74 @@ describe('Bitcoin Service', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f';
|
var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f';
|
||||||
bitcoind.getTransactionWithBlockInfo(txid, function(err) {
|
bitcoind.getDetailedTransaction(txid, function(err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.should.be.instanceof(errors.RPCError);
|
err.should.be.instanceof(errors.RPCError);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should give a transaction with height and timestamp', function(done) {
|
it('should give a transaction with all properties', function(done) {
|
||||||
var bitcoind = new BitcoinService(baseConfig);
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
bitcoind.nodes.push({
|
bitcoind.nodes.push({
|
||||||
client: {
|
client: {
|
||||||
getRawTransaction: sinon.stub().callsArgWith(2, null, {
|
getRawTransaction: sinon.stub().callsArgWith(2, null, {
|
||||||
result: {
|
result: rpcRawTransaction
|
||||||
hex: txBuffer.toString('hex'),
|
|
||||||
blockhash: info.blockHash,
|
|
||||||
height: info.height,
|
|
||||||
time: info.timestamp,
|
|
||||||
vout: [
|
|
||||||
{
|
|
||||||
spentTxId: 'txid',
|
|
||||||
spentIndex: 2,
|
|
||||||
spentHeight: 100
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f';
|
var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f';
|
||||||
bitcoind.getTransactionWithBlockInfo(txid, function(err, tx) {
|
bitcoind.getDetailedTransaction(txid, function(err, tx) {
|
||||||
should.equal(tx.__blockHash, '00000000000ec715852ea2ecae4dc8563f62d603c820f81ac284cd5be0a944d6');
|
|
||||||
should.equal(tx.__height, 530482);
|
|
||||||
should.equal(tx.__timestamp, 1439559434000);
|
|
||||||
should.exist(tx);
|
should.exist(tx);
|
||||||
|
should.not.exist(tx.coinbase);
|
||||||
|
should.equal(tx.hex, txBuffer.toString('hex'));
|
||||||
|
should.equal(tx.blockHash, '00000000000ec715852ea2ecae4dc8563f62d603c820f81ac284cd5be0a944d6');
|
||||||
|
should.equal(tx.height, 530482);
|
||||||
|
should.equal(tx.blockTimestamp, 1439559434000);
|
||||||
|
should.equal(tx.version, 1);
|
||||||
|
should.equal(tx.locktime, 411451);
|
||||||
|
should.equal(tx.feeSatoshis, 10);
|
||||||
|
should.equal(tx.inputSatoshis, 110);
|
||||||
|
should.equal(tx.outputSatoshis, 100);
|
||||||
|
should.equal(tx.hash, txid);
|
||||||
|
var input = tx.inputs[0];
|
||||||
|
should.equal(input.prevTxId, '3d003413c13eec3fa8ea1fe8bbff6f40718c66facffe2544d7516c9e2900cac2');
|
||||||
|
should.equal(input.outputIndex, 0);
|
||||||
|
should.equal(input.satoshis, 110);
|
||||||
|
should.equal(input.sequence, 0xFFFFFFFF);
|
||||||
|
should.equal(input.script, 'scriptSigHex');
|
||||||
|
should.equal(input.scriptAsm, 'scriptSigAsm');
|
||||||
|
should.equal(input.address, 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW');
|
||||||
|
var output = tx.outputs[0];
|
||||||
|
should.equal(output.satoshis, 100);
|
||||||
|
should.equal(output.script, '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac');
|
||||||
|
should.equal(output.scriptAsm, 'OP_DUP OP_HASH160 0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc OP_EQUALVERIFY OP_CHECKSIG');
|
||||||
|
should.equal(output.address, 'mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW');
|
||||||
|
should.equal(output.spentTxId, '4316b98e7504073acd19308b4b8c9f4eeb5e811455c54c0ebfe276c0b1eb6315');
|
||||||
|
should.equal(output.spentIndex, 2);
|
||||||
|
should.equal(output.spentHeight, 100);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should set coinbase to true', function(done) {
|
||||||
|
var bitcoind = new BitcoinService(baseConfig);
|
||||||
|
var rawTransaction = _.clone(rpcRawTransaction);
|
||||||
|
delete rawTransaction.vin[0];
|
||||||
|
rawTransaction.vin = [
|
||||||
|
{
|
||||||
|
coinbase: 'abcdef'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bitcoind.nodes.push({
|
||||||
|
client: {
|
||||||
|
getRawTransaction: sinon.stub().callsArgWith(2, null, {
|
||||||
|
result: rawTransaction
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var txid = '2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f';
|
||||||
|
bitcoind.getDetailedTransaction(txid, function(err, tx) {
|
||||||
|
should.exist(tx);
|
||||||
|
should.equal(tx.coinbase, true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user