diff --git a/src/scripts.js b/src/scripts.js index a442c47..ee317bb 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -136,31 +136,30 @@ function isMultisigOutput() { if (this.chunks < 4) return false if (this.chunks[this.chunks.length - 1] !== opcodes.OP_CHECKMULTISIG) return false - var mS = this.chunks[0] - if (!isSmallIntOp(mS)) return false + var mOp = this.chunks[0] + if (mOp === opcodes.OP_0) return false + if (mOp < opcodes.OP_1) return false + if (mOp > opcodes.OP_16) return false - var nS = this.chunks[this.chunks.length - 2] - if (!isSmallIntOp(nS)) return false + var nOp = this.chunks[this.chunks.length - 2] + if (nOp === opcodes.OP_0) return false + if (nOp < opcodes.OP_1) return false + if (nOp > opcodes.OP_16) return false - var m = mS - (opcodes.OP_1 - 1) - var n = nS - (opcodes.OP_1 - 1) + var m = mOp - (opcodes.OP_1 - 1) + var n = nOp - (opcodes.OP_1 - 1) if (n < m) return false - if (n === 0) return false - if (m > (this.chunks.length - 3)) return false - return this.chunks.slice(1, -2).every(isCanonicalPubKey) + var pubKeys = this.chunks.slice(1, -2) + if (n < pubKeys.length) return false + + return pubKeys.every(isCanonicalPubKey) } function isNulldataOutput() { return this.chunks[0] === opcodes.OP_RETURN } -function isSmallIntOp(opcode) { - if (Buffer.isBuffer(opcode)) return false - - return ((opcode === opcodes.OP_0) || ((opcode >= opcodes.OP_1) && (opcode <= opcodes.OP_16))) -} - // Standard Script Templates // {pubKey} OP_CHECKSIG function pubKeyOutput(pubKey) { diff --git a/test/fixtures/scripts.json b/test/fixtures/scripts.json index 3728e6e..666ea59 100644 --- a/test/fixtures/scripts.json +++ b/test/fixtures/scripts.json @@ -51,6 +51,32 @@ } ], "invalid": { + "classify": [ + { + "description": "multisig output : m > n", + "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1 OP_CHECKMULTISIG" + }, + { + "description": "multisig output : n === 0", + "scriptPubKey": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_0 OP_CHECKMULTISIG" + }, + { + "description": "multisig output : not (m <= len(pubKeys) <= n)", + "scriptPubKey": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_2 OP_CHECKMULTISIG" + }, + { + "description": "multisig output : m not a small int", + "scriptPubKey": "OP_HASH160 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_1 OP_CHECKMULTISIG" + }, + { + "description": "multisig output : n not a small int", + "scriptPubKey": "OP_1 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_HASH160 OP_CHECKMULTISIG" + }, + { + "description": "multisig output : non-canonical pubKey (bad length)", + "scriptPubKey": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffff OP_1 OP_CHECKMULTISIG" + } + ], "multisig": [ { "exception": "Not enough pubKeys provided", diff --git a/test/scripts.js b/test/scripts.js index 7376206..b50ec3a 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -32,6 +32,15 @@ describe('Scripts', function() { assert.equal(type, f.type) }) }) + + fixtures.invalid.classify.forEach(function(f) { + it('returns nonstandard for ' + f.description, function() { + var script = Script.fromASM(f.scriptPubKey) + var type = scripts.classifyOutput(script) + + assert.equal(type, 'nonstandard') + }) + }) }) describe('pubKey', function() {