diff --git a/lib/errors/spec.js b/lib/errors/spec.js index eece532..6093724 100644 --- a/lib/errors/spec.js +++ b/lib/errors/spec.js @@ -24,7 +24,7 @@ module.exports = [{ name: 'InvalidArgument', message: function() { return 'Invalid Argument' + (arguments[0] ? (': ' + arguments[0]) : '') + - (arguments[1] ? (' Documentation: ' + docsURL + arguments[1]): ''); + (arguments[1] ? (' Documentation: ' + docsURL + arguments[1]) : ''); } }, { name: 'AbstractMethodInvoked', @@ -53,6 +53,9 @@ module.exports = [{ errors: [{ name: 'MissingScript', message: 'Need a script to create an input' + }, { + name: 'UnsupportedScript', + message: 'Unsupported input script type: {0}' }] }, { name: 'NeedMoreInfo', diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index e164559..eba0bd8 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -226,33 +226,46 @@ Transaction.prototype.toObject = function toObject() { this.outputs.forEach(function(output) { outputs.push(output.toObject()); }); - return { - changeScript: this._changeScript ? this._changeScript.toString() : undefined, - changeIndex: !_.isUndefined(this._changeIndex) ? this._changeIndex : undefined, - fee: this._fee ? this._fee : undefined, + var obj = { version: this.version, inputs: inputs, outputs: outputs, nLockTime: this.nLockTime }; + if (this._changeScript) { + obj.changeScript = this._changeScript.toString(); + } + if (!_.isUndefined(this._changeIndex)) { + obj.changeIndex = this._changeIndex; + } + if (!_.isUndefined(this._fee)) { + obj.fee = this._fee; + } + return obj; }; Transaction.prototype.fromObject = function(transaction) { var self = this; _.each(transaction.inputs, function(input) { - if (input.output && input.output.script) { - input.output.script = new Script(input.output.script); - if (input.output.script.isPublicKeyHashOut()) { - self.addInput(new Input.PublicKeyHash(input)); - return; - } else if (input.output.script.isScriptHashOut() && input.publicKeys && input.threshold) { - self.addInput(new Input.MultiSigScriptHash( - input, input.publicKeys, input.threshold, input.signatures - )); - return; - } + if (!input.output || !input.output.script) { + self.uncheckedAddInput(new Input(input)); + return; + } + input.output.script = new Script(input.output.script); + var txin; + if (input.output.script.isPublicKeyHashOut()) { + console.log('p2pkh'); + console.log(input.output.script); + txin = new Input.PublicKeyHash(input); + } else if (input.output.script.isScriptHashOut() && input.publicKeys && input.threshold) { + console.log('p2sh'); + txin = new Input.MultiSigScriptHash( + input, input.publicKeys, input.threshold, input.signatures + ); + } else { + throw new errors.Transaction.Input.UnsupportedScript(input.output.script); } - self.uncheckedAddInput(new Input(input)); + self.addInput(txin); }); _.each(transaction.outputs, function(output) { self.addOutput(new Output(output)); diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index 641cd9c..aab1b22 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -490,12 +490,20 @@ describe('Transaction', function() { }).to.throw(errors.Transaction.NLockTimeOutOfRange); }); }); + it('handles anyone-can-spend utxo', function() { var transaction = new Transaction() .from(anyoneCanSpendUTXO) .to(toAddress, 50000); should.exist(transaction); }); + + it('handles unsupported utxo in tx object', function() { + var transaction = new Transaction(); + transaction.fromJSON.bind(transaction, unsupportedTxObj) + .should.throw('Unsupported input script type: OP_1 OP_ADD OP_2 OP_EQUAL'); + }); + }); var tx_empty_hex = '01000000000000000000'; @@ -506,3 +514,5 @@ var tx_1_id = '779a3e5b3c2c452c85333d8521f804c1a52800e60f4b7c3bbe36f4bab350b72c' var tx2hex = '0100000001e07d8090f4d4e6fcba6a2819e805805517eb19e669e9d2f856b41d4277953d640000000091004730440220248bc60bb309dd0215fbde830b6371e3fdc55685d11daa9a3c43828892e26ce202205f10cd4011f3a43657260a211f6c4d1fa81b6b6bdd6577263ed097cc22f4e5b50147522102fa38420cec94843ba963684b771ba3ca7ce1728dc2c7e7cade0bf298324d6b942103f948a83c20b2e7228ca9f3b71a96c2f079d9c32164cd07f08fbfdb483427d2ee52aeffffffff01180fe200000000001976a914ccee7ce8e8b91ec0bc23e1cfb6324461429e6b0488ac00000000'; + +var unsupportedTxObj = '{"version":1,"inputs":[{"prevTxId":"a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458","outputIndex":0,"sequenceNumber":4294967295,"script":"OP_1","output":{"satoshis":1020000,"script":"OP_1 OP_ADD OP_2 OP_EQUAL"}}],"outputs":[{"satoshis":1010000,"script":"OP_DUP OP_HASH160 20 0x7821c0a3768aa9d1a37e16cf76002aef5373f1a8 OP_EQUALVERIFY OP_CHECKSIG"}],"nLockTime":0}';