increase coverage for Input and Output, fix some bugs

This commit is contained in:
Manuel Araoz 2015-02-27 18:27:56 -03:00
parent 5d3b8fbbfb
commit b92fd915eb
5 changed files with 99 additions and 27 deletions

View File

@ -1,6 +1,7 @@
'use strict';
var _ = require('lodash');
var $ = require('../../util/preconditions');
var errors = require('../../errors');
var BufferWriter = require('../../encoding/bufferwriter');
var buffer = require('buffer');
@ -10,6 +11,9 @@ var Script = require('../../script');
var Sighash = require('../sighash');
var Output = require('../output');
var DEFAULT_SEQNUMBER = 0xFFFFFFFF;
function Input(params) {
if (!(this instanceof Input)) {
return new Input(params);
@ -19,6 +23,8 @@ function Input(params) {
}
}
Input.DEFAULT_SEQNUMBER = DEFAULT_SEQNUMBER;
Object.defineProperty(Input.prototype, 'script', {
configurable: false,
writeable: false,
@ -37,9 +43,10 @@ Input.prototype._fromObject = function(params) {
}
this.output = params.output ?
(params.output instanceof Output ? params.output : new Output(params.output)) : undefined;
this.prevTxId = params.prevTxId;
this.outputIndex = params.outputIndex;
this.sequenceNumber = params.sequenceNumber;
this.prevTxId = params.prevTxId || params.txidbuf;
this.outputIndex = _.isUndefined(params.outputIndex) ? params.txoutnum : params.outputIndex;
this.sequenceNumber = _.isUndefined(params.sequenceNumber) ?
(_.isUndefined(params.seqnum) ? DEFAULT_SEQNUMBER : params.seqnum) : params.sequenceNumber;
if (_.isUndefined(params.script) && _.isUndefined(params.scriptBuffer)) {
throw new errors.Transaction.Input.MissingScript();
}
@ -57,21 +64,19 @@ Input.prototype.toObject = function toObject() {
};
};
Input.fromObject = function(obj) {
$.checkArgument(_.isObject(obj));
var input = new Input();
return input._fromObject(obj);
};
Input.prototype.toJSON = function toJSON() {
return JSON.stringify(this.toObject());
};
Input.fromJSON = function(json) {
if (JSUtil.isValidJSON(json)) {
json = JSON.parse(json);
}
return new Input({
output: json.output ? new Output(json.output) : undefined,
prevTxId: json.prevTxId || json.txidbuf,
outputIndex: _.isUndefined(json.outputIndex) ? json.txoutnum : json.outputIndex,
sequenceNumber: json.sequenceNumber || json.seqnum,
scriptBuffer: new Script(json.script, 'hex')
});
$.checkArgument(JSUtil.isValidJSON(json), 'Invalid JSON provided to Input.fromJSON');
return Input.fromObject(JSON.parse(json));
};
Input.fromBufferReader = function(br) {
@ -107,7 +112,7 @@ Input.prototype.setScript = function(script) {
this._script = null;
this._scriptBuffer = new buffer.Buffer(script);
} else {
throw new TypeError('Invalid Argument');
throw new TypeError('Invalid argument type: script');
}
return this;
};
@ -163,9 +168,7 @@ Input.prototype.isNull = function() {
};
Input.prototype._estimateSize = function() {
var bufferWriter = new BufferWriter();
this.toBufferWriter(bufferWriter);
return bufferWriter.toBuffer().length;
return this.toBufferWriter().toBuffer().length;
};
module.exports = Input;

View File

@ -77,7 +77,7 @@ Output.fromJSON = function(json) {
json = JSON.parse(json);
}
return new Output({
satoshis: json.satoshis || -(-json.valuebn),
satoshis: json.satoshis || +json.valuebn,
script: new Script(json.script)
});
};
@ -93,7 +93,7 @@ Output.prototype.setScript = function(script) {
this._scriptBuffer = script;
this._script = null;
} else {
throw new TypeError('Unrecognized Argument');
throw new TypeError('Invalid argument type: script');
}
return this;
};

View File

@ -60,7 +60,6 @@ function Transaction(serialized) {
var CURRENT_VERSION = 1;
var DEFAULT_NLOCKTIME = 0;
var DEFAULT_SEQNUMBER = 0xFFFFFFFF;
// Minimum amount for an output for it not to be considered a dust output
Transaction.DUST_AMOUNT = 546;
@ -516,7 +515,6 @@ Transaction.prototype._fromNonP2SH = function(utxo) {
}),
prevTxId: utxo.txId,
outputIndex: utxo.outputIndex,
sequenceNumber: DEFAULT_SEQNUMBER,
script: Script.empty()
}));
};
@ -532,7 +530,6 @@ Transaction.prototype._fromMultisigUtxo = function(utxo, pubkeys, threshold) {
}),
prevTxId: utxo.txId,
outputIndex: utxo.outputIndex,
sequenceNumber: DEFAULT_SEQNUMBER,
script: Script.empty()
}, pubkeys, threshold));
};

View File

@ -30,6 +30,14 @@ describe('Transaction.Input', function() {
script: new Script(),
satoshis: 1000000
};
var coinbaseJSON = '{"prevTxId":"0000000000000000000000000000000000000000000000000000000000000000"' +
',"outputIndex":4294967295,"script":""}';
var otherJSON = '{"txidbuf":"a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458"' +
',"txoutnum":0,"seqnum":4294967295,"script":"71 0x3044022006553276ec5b885ddf5cc1d7' +
'9e1e3dadbb404b60ad4cc00318e215654f13242102200757c17b36e3d0492fb9cf597032e5afbea67a59274e64af' +
'5a05d12e5ea2303901 33 0x0223078d2942df62c45621d209fab84ea9a7a23346201b7727b9b45a29c4e76f5e",' +
'"output":{"satoshis":100000,"script":"OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b' +
'912911f2a OP_EQUALVERIFY OP_CHECKSIG"}}';
it('has abstract methods: "getSignatures", "isFullySigned", "addSignature", "clearSignatures"', function() {
var input = new Input(output);
@ -41,6 +49,39 @@ describe('Transaction.Input', function() {
});
it('detects coinbase transactions', function() {
new Input(output).isNull().should.equal(false);
new Input(coinbase).isNull().should.equal(true);
var ci = new Input(coinbase);
ci.isNull().should.equal(true);
});
describe('instantiation', function() {
it('works without new', function() {
var input = Input();
should.exist(input);
});
it('fails with no script info', function() {
expect(function() {
var input = new Input({});
input.toString();
}).to.throw('Need a script to create an input');
});
it('fromJSON', function() {
var input = Input.fromJSON(coinbaseJSON);
var otherInput = Input.fromJSON(otherJSON);
should.exist(input);
should.exist(otherInput);
});
it('fromObject', function() {
var input = Input.fromJSON(coinbaseJSON);
var obj = input.toObject();
obj.script = new Buffer(obj.script, 'hex');
Input.fromObject(obj).should.deep.equal(input);
obj.script = 42;
Input.fromObject.bind(null, obj).should.throw('Invalid argument type: script');
});
});
it('_estimateSize', function() {
var input = new Input(output);
input._estimateSize().should.equal(66);
});
});

View File

@ -17,10 +17,16 @@ var errors = bitcore.errors;
describe('Output', function() {
var output = new Output({satoshis: 0, script: Script.empty()});
var output = new Output({
satoshis: 0,
script: Script.empty()
});
it('can be assigned a satoshi amount in big number', function() {
var newOutput = new Output({satoshis: new BN(100), script: Script.empty()});
var newOutput = new Output({
satoshis: new BN(100),
script: Script.empty()
});
newOutput.satoshis.should.equal(100);
});
@ -37,7 +43,10 @@ describe('Output', function() {
});
it('roundtrips to/from object', function() {
var newOutput = new Output({satoshis: 50, script: new Script().add(0)});
var newOutput = new Output({
satoshis: 50,
script: new Script().add(0)
});
var otherOutput = new Output(newOutput.toObject());
expectEqualOutputs(newOutput, otherOutput);
});
@ -47,8 +56,30 @@ describe('Output', function() {
newOutput.setScript(Script().add(0).toBuffer());
newOutput.inspect().should.equal('<Output (0 sats) <Script: OP_0>>');
});
it('has a inspect property', function() {
output.inspect().should.equal('<Output (0 sats) <Script: >>');
});
var output2 = new Output({
satoshis: 1100000000,
script: new Script('OP_2 21 0x038282263212c609d9ea2a6e3e172de238d8c39' +
'cabd5ac1ca10646e23fd5f51508 21 0x038282263212c609d9ea2a6e3e172de23' +
'8d8c39cabd5ac1ca10646e23fd5f51508 OP_2 OP_CHECKMULTISIG OP_EQUAL')
});
it('toBufferWriter', function() {
output2.toBufferWriter().toBuffer().toString('hex')
.should.equal('00ab904100000000485215038282263212c609d9ea2a6e3e172de2' +
'38d8c39cabd5ac1ca10646e23fd5f5150815038282263212c609d9ea2a6e3e172d' +
'e238d8c39cabd5ac1ca10646e23fd5f5150852ae87');
});
it('to/from JSON', function() {
var json = output2.toJSON();
var o3 = new Output(json);
o3.toJSON().should.equal(json);
});
it('setScript fails with invalid input', function() {
var out = new Output(output2.toJSON());
out.setScript.bind(out, 45).should.throw('Invalid argument type: script');
});
});