From 8acf093339655d1c854d146db87cf70de1a08417 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 31 Mar 2014 15:16:30 -0300 Subject: [PATCH] multisign test for signing twice with same sig --- TransactionBuilder.js | 50 +++++++++++++++++++++++++++------ examples/CreateKey.js | 4 +-- test/test.TransactionBuilder.js | 47 ++++++++++++++++++++++++++----- 3 files changed, 84 insertions(+), 17 deletions(-) diff --git a/TransactionBuilder.js b/TransactionBuilder.js index d1b9ed6..e4504d5 100644 --- a/TransactionBuilder.js +++ b/TransactionBuilder.js @@ -58,7 +58,7 @@ * * @opts * { - * remainderAddress: null, + * remainderOut: null, * fee: 0.001, * lockTime: null, * spendUnconfirmed: false, @@ -67,8 +67,12 @@ * Amounts are in BTC. instead of fee and amount; feeSat and amountSat can be given, * repectively, to provide amounts in satoshis. * - * If no remainderAddress is given, and there are remainder coins, the - * first IN address will be used to return the coins. (TODO: is this is reasonable?) + * If no remainderOut is given, and there are remainder coins, the + * first IN out will be used to return the coins. remainderOut has the form: + * remainderOut = { address: 1xxxxx} +* or + * remainderOut = { pubkeys: ['hex1','hex2',...} for multisig + * * */ @@ -101,7 +105,7 @@ function TransactionBuilder(opts) { if (opts.fee || opts.feeSat) { this.givenFeeSat = opts.fee ? opts.fee * util.COIN : opts.feeSat; } - this.remainderAddress = opts.remainderAddress; + this.remainderOut = opts.remainderOut; this.signhash = opts.signhash || Transaction.SIGHASH_ALL; this.tx = {}; @@ -134,6 +138,31 @@ TransactionBuilder._scriptForAddress = function(addressString) { return script; }; + +TransactionBuilder._scriptForPubkeys = function(out) { + + var l = out.pubkeys.length; + var pubKeyBuf=[]; + + for (var i=0; i 1) + ret = this._scriptForPubkeys(out); + else + throw new Error('unknow out type'); + + return ret; +}; + TransactionBuilder.prototype.setUnspent = function(utxos) { this.utxos = utxos; return this; @@ -279,9 +308,9 @@ TransactionBuilder.prototype._setRemainder = function(remainderIndex) { } if (remainderSat.cmp(0) > 0) { - var remainderAddress = this.remainderAddress || this.selectedUtxos[0].address; + var remainderOut = this.remainderOut || this.selectedUtxos[0]; var value = util.bigIntToValue(remainderSat); - var script = TransactionBuilder._scriptForAddress(remainderAddress); + var script = TransactionBuilder._scriptForOut(remainderOut); var txout = { v: value, s: script.getBuffer(), @@ -327,7 +356,7 @@ TransactionBuilder.prototype.setOutputs = function(outs) { for (var i = 0; i < l; i++) { var amountSat = outs[i].amountSat || util.parseValue(outs[i].amount); var value = util.bigIntToValue(amountSat); - var script = TransactionBuilder._scriptForAddress(outs[i].address); + var script = TransactionBuilder._scriptForOut(outs[i]); var txout = { v: value, s: script.getBuffer(), @@ -552,15 +581,20 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig }; }; +TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txSigHash) { + if (!this.hashToScriptMap) + throw new Error('hashToScriptMap not set'); + throw new Error('TX_SCRIPTHASH not supported yet'); +}; + var fnToSign = {}; fnToSign[Script.TX_PUBKEYHASH] = TransactionBuilder.prototype._signPubKeyHash; fnToSign[Script.TX_PUBKEY] = TransactionBuilder.prototype._signPubKey; fnToSign[Script.TX_MULTISIG] = TransactionBuilder.prototype._signMultiSig; fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash; -//if (!this.hashToScriptMap) throw new Error('hashToScriptMap not set'); TransactionBuilder.prototype.sign = function(keys) { this._checkTx(); diff --git a/examples/CreateKey.js b/examples/CreateKey.js index 8b162cf..3264d3e 100644 --- a/examples/CreateKey.js +++ b/examples/CreateKey.js @@ -3,12 +3,12 @@ var run = function() { - // Replace '../bitcore' with 'bitcore' if you use this code elsewhere. + // replace '../bitcore' with 'bitcore' if you use this code elsewhere. var bitcore = require('../bitcore'); var networks = require('../networks'); var WalletKey = bitcore.WalletKey; - var opts = {network: networks.livenet}; + var opts = {network: networks.testnet}; function print(wk) { diff --git a/test/test.TransactionBuilder.js b/test/test.TransactionBuilder.js index 6bc6bd7..d848a3c 100644 --- a/test/test.TransactionBuilder.js +++ b/test/test.TransactionBuilder.js @@ -104,7 +104,7 @@ describe('TransactionBuilder', function() { var getBuilder2 = function (fee) { var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, spendUnconfirmed: true, }; @@ -134,7 +134,7 @@ describe('TransactionBuilder', function() { var utxos = testdata.dataUnspent; var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, spendUnconfirmed: true, }; var outs = [{ @@ -211,7 +211,7 @@ describe('TransactionBuilder', function() { var getBuilder3 = function (outs) { var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, spendUnconfirmed: true, }; @@ -397,7 +397,7 @@ describe('TransactionBuilder', function() { it('should sign a p2pubkey tx', function() { var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, }; var outs = outs || [{ address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', @@ -419,7 +419,7 @@ describe('TransactionBuilder', function() { it('should sign a multisig tx', function() { var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, }; var outs = outs || [{ address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', @@ -440,7 +440,7 @@ describe('TransactionBuilder', function() { it('should sign a multisig tx in steps (3-5)', function() { var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, }; var outs = outs || [{ address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', @@ -470,7 +470,7 @@ describe('TransactionBuilder', function() { it('should count multisig signs (3-5)', function() { var opts = { - remainderAddress: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd', + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, }; var outs = outs || [{ address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', @@ -494,7 +494,40 @@ describe('TransactionBuilder', function() { b.sign(k3); b.isFullySigned().should.equal(true); b.countInputMultiSig(0).should.equal(3); + }); + it('should avoid siging with the same key twice multisig signs (3-5)', function() { + var opts = { + remainderOut: {address: 'mwZabyZXg8JzUtFX1pkGygsMJjnuqiNhgd'}, + }; + var outs = outs || [{ + address: 'mrPnbY1yKDBsdgbHbS7kJ8GVm8F66hWHLE', + amount: 0.08 + }]; + var b = new TransactionBuilder(opts) + .setUnspent(testdata.dataUnspentSign.unspentMulti) + .setOutputs(outs); + + var k1 = testdata.dataUnspentSign.keyStringsMulti.slice(0,1); + var k23 = testdata.dataUnspentSign.keyStringsMulti.slice(1,3); + + b.countInputMultiSig(0).should.equal(0); + b.sign(k1); + b.isFullySigned().should.equal(false); + b.countInputMultiSig(0).should.equal(1); + b.sign(k1); + b.isFullySigned().should.equal(false); + b.countInputMultiSig(0).should.equal(1); + b.sign(k1); + b.isFullySigned().should.equal(false); + b.countInputMultiSig(0).should.equal(1); + + + + + b.sign(k23); + b.isFullySigned().should.equal(true); + b.countInputMultiSig(0).should.equal(3); }); });