From a4b8c06a2dfad69a4d608c84dc2e8fc31fb1165a Mon Sep 17 00:00:00 2001 From: Gregg Zigler Date: Wed, 24 Jun 2015 13:30:25 -0400 Subject: [PATCH 1/4] get-signature-count needed to measure txs with many inputs or outputs --- lib/script/script.js | 39 +++++++++++++++++++++++++++++++++++++++ test/script/script.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/lib/script/script.js b/lib/script/script.js index 7b680a6..54f629d 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -838,4 +838,43 @@ Script.prototype.checkMinimalPush = function(i) { return true; }; +/** + * Comes from bitcoind's script DecodOP_N function + * @param {number} opcode + * @returns {number} numeric value in range of -1 to 16 + */ +Script.prototype._decodeOP_N = function(opcode) { + if (opcode === Opcode.OP_0) + return 0; + else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) + return opcode - (Opcode.OP_1 - 1); + else + throw new Error('Invalid opcode: ' + JSON.stringify(opcode)); +}; + +/** + * Comes from bitcoind's script GetSigOpCount(boolean) function + * @param {boolean} use current (true) or pre-version-0.6 (false) logic + * @returns {number} number of signature operations required by this script + */ +Script.prototype.getSignatureOperationsCount = function(fAccurate) { + var self = this; + var n = 0; + var lastOpcode = Opcode.OP_INVALIDOPCODE; + _.each(self.chunks, function getChunkOther(chunk) { + var opcode = chunk.opcodenum; + if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) + n++; + else if (opcode == Opcode.OP_CHECKMULTISIG || + opcode == Opcode.OP_CHECKMULTISIGVERIFY) { + if (fAccurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) + n += self._decodeOP_N(lastOpcode); + else + n += 20; + } + lastOpcode = opcode; + }); + return n; +}; + module.exports = Script; diff --git a/test/script/script.js b/test/script/script.js index 21a23b5..46462f4 100644 --- a/test/script/script.js +++ b/test/script/script.js @@ -775,5 +775,38 @@ describe('Script', function() { }); }); + describe('#getSignatureOperationsCount', function() { + // comes from bitcoind src/test/sigopcount_tests + // only test calls to function with boolean param, not signature ref param + it('should match bitcoind behavior', function() { + Script().getSignatureOperationsCount(false).should.equal(0); + Script().getSignatureOperationsCount(true).should.equal(0); + var s1 = 'OP_1 01 FF OP_2 OP_CHECKMULTISIG'; + Script(s1).getSignatureOperationsCount(true).should.equal(2); + s1 += ' OP_IF OP_CHECKSIG OP_ENDIF'; + Script(s1).getSignatureOperationsCount(true).should.equal(3); + Script(s1).getSignatureOperationsCount(false).should.equal(21); + // do not test BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); + + var pubkey_hexs = [ + '022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', + '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', + '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', + ]; + var sortkeys = pubkey_hexs.slice(0, 3).map(PublicKey); + var s2 = Script.buildMultisigOut(sortkeys, 1); + Script(s2).getSignatureOperationsCount(true).should.equal(3); + Script(s2).getSignatureOperationsCount(false).should.equal(20); + + // create a bogus, well-formed signature + var signature = bitcore.crypto.Signature.fromString('30060201FF0201FF'); + var signatures = [ signature.toBuffer() ]; + var p2sh = Script.buildP2SHMultisigIn(pubkey_hexs, 1, signatures, {}); + p2sh.getSignatureOperationsCount(true).should.equal(0); + p2sh.getSignatureOperationsCount(false).should.equal(0); + + // do not test BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); + }); + }); }); From 183ffab02b4ae87dc051923b2a73cef76714ffbc Mon Sep 17 00:00:00 2001 From: Gregg Zigler Date: Wed, 24 Jun 2015 14:18:55 -0400 Subject: [PATCH 2/4] match bitcore style standards, rename arg, set default to true --- lib/script/script.js | 22 ++++++++++++---------- test/script/script.js | 44 ++++++++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/script/script.js b/lib/script/script.js index 54f629d..f32d768 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -841,15 +841,16 @@ Script.prototype.checkMinimalPush = function(i) { /** * Comes from bitcoind's script DecodOP_N function * @param {number} opcode - * @returns {number} numeric value in range of -1 to 16 + * @returns {number} numeric value in range of 0 to 16 */ Script.prototype._decodeOP_N = function(opcode) { - if (opcode === Opcode.OP_0) + if (opcode === Opcode.OP_0) { return 0; - else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) + } else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) { return opcode - (Opcode.OP_1 - 1); - else + } else { throw new Error('Invalid opcode: ' + JSON.stringify(opcode)); + } }; /** @@ -857,20 +858,21 @@ Script.prototype._decodeOP_N = function(opcode) { * @param {boolean} use current (true) or pre-version-0.6 (false) logic * @returns {number} number of signature operations required by this script */ -Script.prototype.getSignatureOperationsCount = function(fAccurate) { +Script.prototype.getSignatureOperationsCount = function(accurate) { var self = this; + accurate = (typeof accurate == 'undefined') ? true : accurate; var n = 0; var lastOpcode = Opcode.OP_INVALIDOPCODE; _.each(self.chunks, function getChunkOther(chunk) { var opcode = chunk.opcodenum; - if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) + if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) { n++; - else if (opcode == Opcode.OP_CHECKMULTISIG || - opcode == Opcode.OP_CHECKMULTISIGVERIFY) { - if (fAccurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) + } else if (opcode == Opcode.OP_CHECKMULTISIG || opcode == Opcode.OP_CHECKMULTISIGVERIFY) { + if (accurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) { n += self._decodeOP_N(lastOpcode); - else + } else { n += 20; + } } lastOpcode = opcode; }); diff --git a/test/script/script.js b/test/script/script.js index 46462f4..5f5a3c4 100644 --- a/test/script/script.js +++ b/test/script/script.js @@ -778,35 +778,49 @@ describe('Script', function() { describe('#getSignatureOperationsCount', function() { // comes from bitcoind src/test/sigopcount_tests // only test calls to function with boolean param, not signature ref param - it('should match bitcoind behavior', function() { + var pubkey_hexs = [ + '022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', + '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', + '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', + ]; + it('should return zero for empty scripts', function() { Script().getSignatureOperationsCount(false).should.equal(0); Script().getSignatureOperationsCount(true).should.equal(0); + }); + it('should handle multi-sig multisig scripts from string', function() { var s1 = 'OP_1 01 FF OP_2 OP_CHECKMULTISIG'; Script(s1).getSignatureOperationsCount(true).should.equal(2); s1 += ' OP_IF OP_CHECKSIG OP_ENDIF'; Script(s1).getSignatureOperationsCount(true).should.equal(3); Script(s1).getSignatureOperationsCount(false).should.equal(21); - - // do not test BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); - - var pubkey_hexs = [ - '022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', - '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', - '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', - ]; - var sortkeys = pubkey_hexs.slice(0, 3).map(PublicKey); - var s2 = Script.buildMultisigOut(sortkeys, 1); + }); + it.skip('should handle script arg from p2sh object from string', function() { + // BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); + }); + it('should handle multi-sig-out scripts from utility function', function() { + var sortKeys = pubkey_hexs.slice(0, 3).map(PublicKey); + var s2 = Script.buildMultisigOut(sortKeys, 1); Script(s2).getSignatureOperationsCount(true).should.equal(3); Script(s2).getSignatureOperationsCount(false).should.equal(20); - - // create a bogus, well-formed signature + }); + it('should handle P2SH-multisig-in scripts from utility', function() { + // create a well-formed signature, does not need to match pubkeys var signature = bitcore.crypto.Signature.fromString('30060201FF0201FF'); var signatures = [ signature.toBuffer() ]; var p2sh = Script.buildP2SHMultisigIn(pubkey_hexs, 1, signatures, {}); p2sh.getSignatureOperationsCount(true).should.equal(0); p2sh.getSignatureOperationsCount(false).should.equal(0); - - // do not test BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); + }); + it.skip('should handle script arg from p2sh object from utility', function() { + // BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); + }); + it('should default the one and only argument to true', function() { + var s1 = 'OP_1 01 FF OP_2 OP_CHECKMULTISIG'; + var trueCount = Script(s1).getSignatureOperationsCount(true); + var falseCount = Script(s1).getSignatureOperationsCount(false); + var defaultCount = Script(s1).getSignatureOperationsCount(); + trueCount.should.not.equal(falseCount); + trueCount.should.equal(defaultCount); }); }); }); From 77645c7f0301627f353070901db0f8eacf1987b5 Mon Sep 17 00:00:00 2001 From: Gregg Zigler Date: Wed, 24 Jun 2015 14:44:27 -0400 Subject: [PATCH 3/4] remove skipped tests since equalivant boolean tests already exist --- lib/script/script.js | 4 ++-- test/script/script.js | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/script/script.js b/lib/script/script.js index f32d768..f93ace2 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -859,11 +859,11 @@ Script.prototype._decodeOP_N = function(opcode) { * @returns {number} number of signature operations required by this script */ Script.prototype.getSignatureOperationsCount = function(accurate) { + accurate = (_.isUndefined(accurate) ? true : accurate); var self = this; - accurate = (typeof accurate == 'undefined') ? true : accurate; var n = 0; var lastOpcode = Opcode.OP_INVALIDOPCODE; - _.each(self.chunks, function getChunkOther(chunk) { + _.each(self.chunks, function getChunk(chunk) { var opcode = chunk.opcodenum; if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) { n++; diff --git a/test/script/script.js b/test/script/script.js index 5f5a3c4..d5c3661 100644 --- a/test/script/script.js +++ b/test/script/script.js @@ -794,9 +794,6 @@ describe('Script', function() { Script(s1).getSignatureOperationsCount(true).should.equal(3); Script(s1).getSignatureOperationsCount(false).should.equal(21); }); - it.skip('should handle script arg from p2sh object from string', function() { - // BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); - }); it('should handle multi-sig-out scripts from utility function', function() { var sortKeys = pubkey_hexs.slice(0, 3).map(PublicKey); var s2 = Script.buildMultisigOut(sortKeys, 1); @@ -811,9 +808,6 @@ describe('Script', function() { p2sh.getSignatureOperationsCount(true).should.equal(0); p2sh.getSignatureOperationsCount(false).should.equal(0); }); - it.skip('should handle script arg from p2sh object from utility', function() { - // BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); - }); it('should default the one and only argument to true', function() { var s1 = 'OP_1 01 FF OP_2 OP_CHECKMULTISIG'; var trueCount = Script(s1).getSignatureOperationsCount(true); From b6d44f46223749883fc759c0c2a15d181a5ab18f Mon Sep 17 00:00:00 2001 From: Gregg Zigler Date: Thu, 25 Jun 2015 17:53:50 -0400 Subject: [PATCH 4/4] camelCase variable names --- test/script/script.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/script/script.js b/test/script/script.js index d5c3661..dd138a2 100644 --- a/test/script/script.js +++ b/test/script/script.js @@ -471,7 +471,7 @@ describe('Script', function() { }); describe('#buildMultisigOut', function() { - var pubkey_hexs = [ + var pubKeyHexes = [ '022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', @@ -479,7 +479,7 @@ describe('Script', function() { '036a98a36aa7665874b1ba9130bc6d318e52fd3bdb5969532d7fc09bf2476ff842', '033aafcbead78c08b0e0aacc1b0cdb40702a7c709b660bebd286e973242127e15b', ]; - var sortkeys = pubkey_hexs.slice(0, 3).map(PublicKey); + var sortkeys = pubKeyHexes.slice(0, 3).map(PublicKey); it('should create sorted script by default', function() { var s = Script.buildMultisigOut(sortkeys, 2); s.toString().should.equal('OP_2 33 0x021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18 33 0x022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da 33 0x03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9 OP_3 OP_CHECKMULTISIG'); @@ -501,7 +501,7 @@ describe('Script', function() { s.isMultisigOut().should.equal(true); }); var test_mn = function(m, n) { - var pubkeys = pubkey_hexs.slice(0, n).map(PublicKey); + var pubkeys = pubKeyHexes.slice(0, n).map(PublicKey); var s = Script.buildMultisigOut(pubkeys, m); s.isMultisigOut().should.equal(true); }; @@ -778,7 +778,7 @@ describe('Script', function() { describe('#getSignatureOperationsCount', function() { // comes from bitcoind src/test/sigopcount_tests // only test calls to function with boolean param, not signature ref param - var pubkey_hexs = [ + var pubKeyHexes = [ '022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', @@ -795,7 +795,7 @@ describe('Script', function() { Script(s1).getSignatureOperationsCount(false).should.equal(21); }); it('should handle multi-sig-out scripts from utility function', function() { - var sortKeys = pubkey_hexs.slice(0, 3).map(PublicKey); + var sortKeys = pubKeyHexes.slice(0, 3).map(PublicKey); var s2 = Script.buildMultisigOut(sortKeys, 1); Script(s2).getSignatureOperationsCount(true).should.equal(3); Script(s2).getSignatureOperationsCount(false).should.equal(20); @@ -804,7 +804,7 @@ describe('Script', function() { // create a well-formed signature, does not need to match pubkeys var signature = bitcore.crypto.Signature.fromString('30060201FF0201FF'); var signatures = [ signature.toBuffer() ]; - var p2sh = Script.buildP2SHMultisigIn(pubkey_hexs, 1, signatures, {}); + var p2sh = Script.buildP2SHMultisigIn(pubKeyHexes, 1, signatures, {}); p2sh.getSignatureOperationsCount(true).should.equal(0); p2sh.getSignatureOperationsCount(false).should.equal(0); });