Tests for transaction
This commit is contained in:
parent
0cd5323261
commit
a619f9c277
@ -125,7 +125,13 @@ var blockNotFound = function(err) {
|
||||
* @return {Promise<Block>}
|
||||
*/
|
||||
BlockService.prototype.getBlock = function(blockHash) {
|
||||
$.checkArgument(JSUtil.isHexa(blockHash), 'Block hash must be hexa');
|
||||
$.checkArgument(
|
||||
JSUtil.isHexa(blockHash) || bitcore.util.buffer.isBuffer(blockHash),
|
||||
'Block hash must be a buffer or hexa'
|
||||
);
|
||||
if (bitcore.util.buffer.isBuffer(blockHash)) {
|
||||
blockHash = bitcore.util.buffer.reverse(blockHash).toString('hex');
|
||||
}
|
||||
|
||||
var blockData;
|
||||
var self = this;
|
||||
@ -238,6 +244,9 @@ BlockService.prototype._confirmBlock = function(block) {
|
||||
};
|
||||
|
||||
BlockService.prototype._setNextBlock = function(ops, prevBlockHash, block) {
|
||||
if (bitcore.util.buffer.isBuffer(prevBlockHash)) {
|
||||
prevBlockHash = bitcore.util.buffer.reverse(prevBlockHash).toString('hex');
|
||||
}
|
||||
return Promise.try(function() {
|
||||
ops.push({
|
||||
type: 'put',
|
||||
|
||||
@ -37,12 +37,14 @@ var helper = function(name) {
|
||||
};
|
||||
};
|
||||
var helperAddress = function(index) {
|
||||
return function(address) {
|
||||
return function(address, txid, number) {
|
||||
if (_.isString(address)) {
|
||||
address = new bitcore.Address(address);
|
||||
}
|
||||
$.checkArgument(address instanceof bitcore.Address, 'address must be a string or bitcore.Address');
|
||||
return index + address.toString();
|
||||
$.checkArgument(bitcore.util.js.isHexa(txid), 'TXID must be an hexa string');
|
||||
$.checkArgument(_.isNumber(number), 'Input number must be a number');
|
||||
return index + address.toString() + '-' + txid + '-' + number;
|
||||
};
|
||||
};
|
||||
|
||||
@ -115,7 +117,7 @@ TransactionService.prototype._confirmOutput = function(ops, block, transaction)
|
||||
if (address) {
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getOutputsForAddress(address),
|
||||
key: Index.getOutputsForAddress(address, transaction.id, index),
|
||||
value: output.toObject()
|
||||
});
|
||||
}
|
||||
@ -123,29 +125,28 @@ TransactionService.prototype._confirmOutput = function(ops, block, transaction)
|
||||
};
|
||||
|
||||
TransactionService.prototype._confirmInput = function(ops, block, transaction) {
|
||||
var self = this;
|
||||
return function(input, index) {
|
||||
if (input.prevTxId.toString('hex') !== NULLTXHASH) {
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getOutput(transaction.id, index),
|
||||
value: _.extend(input.toObject(), {
|
||||
heightConfirmed: block.height
|
||||
})
|
||||
});
|
||||
var script = input.script;
|
||||
if (script.isPublicKeyHashIn() || script.isScriptHashIn()) {
|
||||
// TODO: Move this logic to bitcore
|
||||
var address = script.isPublicKeyHashIn()
|
||||
? new PublicKey(script.chunks[0].buf).toAddress()
|
||||
: new Script(script.chunks[script.chunks.length - 1]).toAddress();
|
||||
if (input.prevTxId.toString('hex') === NULLTXHASH) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getOutput(transaction.id, index),
|
||||
value: _.extend(input.toObject(), {
|
||||
heightConfirmed: block.height
|
||||
})
|
||||
});
|
||||
var script = input.script;
|
||||
if (!(script.isPublicKeyHashIn() || script.isPublicKeyIn() || script.isScriptHashIn())) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return self._getAddressForInput(input).then(function(address) {
|
||||
if (address) {
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getOutputsForAddress(address),
|
||||
value: input.toObject()
|
||||
});
|
||||
ops.push({
|
||||
type: 'put',
|
||||
key: Index.getSpentOutputsForAddress(address),
|
||||
key: Index.getSpentOutputsForAddress(address, transaction.id, index),
|
||||
value: {
|
||||
heightSpent: block.height,
|
||||
spentTx: transaction.id,
|
||||
@ -154,10 +155,36 @@ TransactionService.prototype._confirmInput = function(ops, block, transaction) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
TransactionService.prototype._getAddressForInput = function(input) {
|
||||
var script = input.script;
|
||||
var self = this;
|
||||
|
||||
if (script.isPublicKeyHashIn()) {
|
||||
var hash = bitcore.crypto.Hash.sha256ripemd160(script.chunks[0].buf);
|
||||
return Promise.resolve(new bitcore.Address(
|
||||
hash, bitcore.Networks.defaultNetwork, bitcore.Address.PayToPublicKeyHash
|
||||
));
|
||||
} else if (script.isPublicKeyIn()) {
|
||||
return self.getTransaction(input.prevTxId.toString('hex')).then(function(transaction) {
|
||||
var outputScript = transaction.outputs[input.outputIndex].script;
|
||||
if (outputScript.isPublicKeyOut()) {
|
||||
return Promise.resolve(new bitcore.Address(
|
||||
bitcore.crypto.Hash.sha256ripemd160(outputScript.chunks[0].buf),
|
||||
bitcore.Networks.defaultNetwork, bitcore.Address.PayToPublicKeyHash
|
||||
));
|
||||
} else {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(new bitcore.Script(script.chunks[script.chunks.length - 1]).toAddress());
|
||||
}
|
||||
};
|
||||
|
||||
TransactionService.prototype._confirmTransaction = function(ops, block, transaction) {
|
||||
var self = this;
|
||||
return Promise.try(function() {
|
||||
@ -166,8 +193,11 @@ TransactionService.prototype._confirmTransaction = function(ops, block, transact
|
||||
key: Index.getBlockForTransaction(transaction),
|
||||
value: block.id
|
||||
});
|
||||
_.each(transaction.outputs, self._confirmOutput(ops, block, transaction));
|
||||
_.each(transaction.inputs, self._confirmInput(ops, block, transaction));
|
||||
return Promise.all(
|
||||
_.each(transaction.outputs, self._confirmOutput(ops, block, transaction))
|
||||
.concat(
|
||||
_.each(transaction.inputs, self._confirmInput(ops, block, transaction))
|
||||
));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -71,7 +71,6 @@
|
||||
"bitcore-build": "bitpay/bitcore-build",
|
||||
"chai": "^2.1.1",
|
||||
"gulp": "^3.8.10",
|
||||
"mocha": "^2.2.1",
|
||||
"should": "^5.1.0",
|
||||
"sinon": "^1.13.0",
|
||||
"supertest": "^0.15.0"
|
||||
|
||||
17
test/data/169.js
Normal file
17
test/data/169.js
Normal file
@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
var block169 = new bitcore.Block(
|
||||
new Buffer(
|
||||
'01000000696aa63f0f22d9189c8536bb83b18737ae8336c25a67937f79957e5600000000982db9870a'
|
||||
+'5e30d8f0b2a4ebccc5852b5a1e2413e9274c4947bfec6bdaa9b9d75bb76a49ffff001d2b719fdd0101'
|
||||
+'000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07'
|
||||
+'04ffff001d0101ffffffff0100f2052a010000004341045da87c7b825c75ca17ade8bb5cdbcd27af4c'
|
||||
+'e97373aa9848c0c84693ca857cf379e14c2ce61ea2aaee9450d0939e21bd26894aa6dcc808656fa997'
|
||||
+'4dc296589eac00000000'
|
||||
, 'hex')
|
||||
);
|
||||
block169.height = 169;
|
||||
|
||||
module.exports = block169;
|
||||
23
test/data/170.js
Normal file
23
test/data/170.js
Normal file
@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
var block170 = new bitcore.Block(
|
||||
new Buffer(
|
||||
'0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000ff104ccb054'
|
||||
+'21ab93e63f8c3ce5c2c2e9dbb37de2764b3a3175c8166562cac7d51b96a49ffff001d283e9e7002010'
|
||||
+'00000010000000000000000000000000000000000000000000000000000000000000000ffffffff070'
|
||||
+'4ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34ee'
|
||||
+'c332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a'
|
||||
+'7ac61725bac000000000100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce2'
|
||||
+'5857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61'
|
||||
+'548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d090'
|
||||
+'1ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd3'
|
||||
+'78d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac0'
|
||||
+'0286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909'
|
||||
+'a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000'
|
||||
, 'hex')
|
||||
);
|
||||
block170.height = 170;
|
||||
|
||||
module.exports = block170;
|
||||
5
test/data/firstTxSpent.js
Normal file
5
test/data/firstTxSpent.js
Normal file
@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
module.exports = new bitcore.Transaction('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0134ffffffff0100f2052a0100000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000');
|
||||
15
test/data/genesis.js
Normal file
15
test/data/genesis.js
Normal file
@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
module.exports = new bitcore.Block(
|
||||
new Buffer(
|
||||
'0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a'
|
||||
+'7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c010'
|
||||
+'1000000010000000000000000000000000000000000000000000000000000000000000000ffffffff'
|
||||
+'4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f7'
|
||||
+'2206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffff'
|
||||
+'ff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0e'
|
||||
+'a1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'
|
||||
, 'hex')
|
||||
);
|
||||
@ -87,17 +87,9 @@ describe('BlockService', function() {
|
||||
return arg();
|
||||
}
|
||||
};
|
||||
var genesisBlock = new bitcore.Block(
|
||||
new Buffer(
|
||||
'0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a'
|
||||
+'7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c010'
|
||||
+'1000000010000000000000000000000000000000000000000000000000000000000000000ffffffff'
|
||||
+'4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f7'
|
||||
+'2206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffff'
|
||||
+'ff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0e'
|
||||
+'a1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'
|
||||
, 'hex')
|
||||
);
|
||||
var genesisBlock = require('../data/genesis');
|
||||
var block169 = require('../data/169');
|
||||
var block170 = require('../data/170');
|
||||
|
||||
beforeEach(function() {
|
||||
database = sinon.mock();
|
||||
@ -110,7 +102,6 @@ describe('BlockService', function() {
|
||||
database: database
|
||||
});
|
||||
blockService.writeLock = sinon.mock();
|
||||
blockService.getBlock = sinon.mock();
|
||||
});
|
||||
|
||||
it('makes the expected calls when confirming the genesis block', function(callback) {
|
||||
@ -133,11 +124,42 @@ describe('BlockService', function() {
|
||||
};
|
||||
blockService.unlock = callback;
|
||||
blockService.writeLock.onFirstCall().returns(thenCaller);
|
||||
blockService.getBlock = sinon.mock();
|
||||
database.getAsync = function() {
|
||||
return Promise.reject({notFound: true});
|
||||
};
|
||||
transactionMock._confirmTransaction = sinon.mock();
|
||||
blockService._confirmBlock(genesisBlock);
|
||||
});
|
||||
|
||||
it('makes the expected calls when confirming the block #170', function(callback) {
|
||||
database.batchAsync = function(ops) {
|
||||
ops.should.deep.equal([
|
||||
{ type: 'put',
|
||||
key: 'nxt-000000002a22cfee1f2c846adbd12b3e183d4f97683f85dad08a79780a84bd55',
|
||||
value: '00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee' },
|
||||
{ type: 'put',
|
||||
key: 'prev-00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee',
|
||||
value: '000000002a22cfee1f2c846adbd12b3e183d4f97683f85dad08a79780a84bd55' },
|
||||
{ type: 'put',
|
||||
key: 'bh-00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee',
|
||||
value: 170 },
|
||||
{ type: 'put',
|
||||
key: 'bts-1231731025',
|
||||
value: '00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee' }
|
||||
]);
|
||||
return thenCaller;
|
||||
};
|
||||
blockService.unlock = callback;
|
||||
blockService.writeLock.onFirstCall().returns(thenCaller);
|
||||
blockService.getBlock = function() {
|
||||
return Promise.resolve(block169);
|
||||
};
|
||||
database.getAsync = function() {
|
||||
return Promise.reject({notFound: true});
|
||||
};
|
||||
transactionMock._confirmTransaction = sinon.spy();
|
||||
blockService._confirmBlock(block170);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,6 +5,7 @@ var should = require('chai').should();
|
||||
var Promise = require('bluebird');
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
var TransactionService = require('../../lib/services/transaction');
|
||||
|
||||
@ -63,17 +64,7 @@ describe('TransactionService', function() {
|
||||
});
|
||||
});
|
||||
|
||||
var genesisBlock = new bitcore.Block(
|
||||
new Buffer(
|
||||
'0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a'
|
||||
+'7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c010'
|
||||
+'1000000010000000000000000000000000000000000000000000000000000000000000000ffffffff'
|
||||
+'4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f7'
|
||||
+'2206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffff'
|
||||
+'ff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0e'
|
||||
+'a1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'
|
||||
, 'hex')
|
||||
);
|
||||
var genesisBlock = require('../data/genesis');
|
||||
genesisBlock.height = 0;
|
||||
var genesisTx = genesisBlock.transactions[0];
|
||||
|
||||
@ -90,7 +81,7 @@ describe('TransactionService', function() {
|
||||
{ satoshis: 5000000000,
|
||||
script: '65 0x04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG' } },
|
||||
{ type: 'put',
|
||||
key: 'txa-1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
|
||||
key: 'txa-1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa-4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b-0',
|
||||
value:
|
||||
{ satoshis: 5000000000,
|
||||
script: '65 0x04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG' } }
|
||||
@ -98,5 +89,65 @@ describe('TransactionService', function() {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
|
||||
var block170 = require('../data/170');
|
||||
|
||||
it('confirms correctly the first non-coinbase transaction (block 170)', function(callback) {
|
||||
var ops = [];
|
||||
service.getTransaction = sinon.stub();
|
||||
var firstTxSpent = require('../data/firstTxSpent');
|
||||
service.getTransaction.onFirstCall().returns({
|
||||
then: function(arg) {
|
||||
return arg(firstTxSpent);
|
||||
}
|
||||
});
|
||||
service._confirmTransaction(ops, block170, block170.transactions[1]).then(function() {
|
||||
ops.should.deep.equal([
|
||||
{ type: 'put',
|
||||
key: 'btx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16',
|
||||
value: '00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee' },
|
||||
{ type: 'put',
|
||||
key: 'txo-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0',
|
||||
value:
|
||||
{ satoshis: 1000000000,
|
||||
script: '65 0x04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_CHECKSIG' } },
|
||||
{ type: 'put',
|
||||
key: 'txa-1Q2TWHE3GMdB6BZKafqwxXtWAWgFt5Jvm3-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0',
|
||||
value:
|
||||
{ satoshis: 1000000000,
|
||||
script: '65 0x04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_CHECKSIG' } },
|
||||
{ type: 'put',
|
||||
key: 'txo-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-1',
|
||||
value:
|
||||
{ satoshis: 4000000000,
|
||||
script: '65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 OP_CHECKSIG' } },
|
||||
{ type: 'put',
|
||||
key: 'txa-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-1',
|
||||
value:
|
||||
{ satoshis: 4000000000,
|
||||
script: '65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 OP_CHECKSIG' } },
|
||||
{ type: 'put',
|
||||
key: 'txo-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0',
|
||||
value:
|
||||
{ prevTxId: '0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9',
|
||||
outputIndex: 0,
|
||||
sequenceNumber: 4294967295,
|
||||
script: '71 0x304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901',
|
||||
output: undefined,
|
||||
heightConfirmed: 170 } },
|
||||
{ type: 'put',
|
||||
key: 'txas-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0',
|
||||
value:
|
||||
{ heightSpent: 170,
|
||||
spentTx: 'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16',
|
||||
spentTxInputIndex: 0,
|
||||
spendInput: { prevTxId: '0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9',
|
||||
outputIndex: 0,
|
||||
sequenceNumber: 4294967295,
|
||||
script: '71 0x304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901',
|
||||
output: undefined }}}]);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user