diff --git a/src/script.js b/src/script.js index 6c75f11..564e5a7 100644 --- a/src/script.js +++ b/src/script.js @@ -3,20 +3,10 @@ var opcodes = require('./opcodes') var typeforce = require('typeforce') var types = require('./types') -function coerceChunks (chunks) { - if (types.Array(chunks)) return chunks - - return decompile(chunks) -} - -function coerceBuffer (buffer) { - if (types.Buffer(buffer)) return buffer - - return compile(buffer) -} - function toASM (chunks) { - chunks = coerceChunks(chunks) + if (types.Buffer(chunks)) { + chunks = decompile(chunks) + } return chunks.map(function (chunk) { // data chunk @@ -45,11 +35,12 @@ function fromASM (asm) { } }) - return chunks + return compile(chunks) } function compile (chunks) { - chunks = coerceChunks(chunks) + // TODO: remove me + if (types.Buffer(chunks)) return chunks typeforce(types.Array, chunks) @@ -86,7 +77,8 @@ function compile (chunks) { } function decompile (buffer) { - buffer = coerceBuffer(buffer) + // TODO: remove me + if (types.Array(buffer)) return buffer typeforce(types.Buffer, buffer) @@ -132,6 +124,6 @@ for (var op in opcodes) { module.exports = { compile: compile, decompile: decompile, - toASM: toASM, - fromASM: fromASM + fromASM: fromASM, + toASM: toASM } diff --git a/src/scripts.js b/src/scripts.js index ec836fb..52c2b6c 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -40,24 +40,16 @@ function isCanonicalSignature (buffer) { return true } -function coerceBuffer (buffer) { - return types.Buffer(buffer) ? buffer : Script.compile(buffer) -} - -function coerceChunks (chunks) { - return types.Array(chunks) ? chunks : Script.decompile(chunks) -} - -function isPubKeyHashInput (chunks) { - chunks = coerceChunks(chunks) +function isPubKeyHashInput (script) { + var chunks = Script.decompile(script) return chunks.length === 2 && isCanonicalSignature(chunks[0]) && isCanonicalPubKey(chunks[1]) } -function isPubKeyHashOutput (chunks) { - chunks = coerceChunks(chunks) +function isPubKeyHashOutput (script) { + var chunks = Script.decompile(script) return chunks.length === 5 && chunks[0] === ops.OP_DUP && @@ -68,23 +60,23 @@ function isPubKeyHashOutput (chunks) { chunks[4] === ops.OP_CHECKSIG } -function isPubKeyInput (chunks) { - chunks = coerceChunks(chunks) +function isPubKeyInput (script) { + var chunks = Script.decompile(script) return chunks.length === 1 && isCanonicalSignature(chunks[0]) } -function isPubKeyOutput (chunks) { - chunks = coerceChunks(chunks) +function isPubKeyOutput (script) { + var chunks = Script.decompile(script) return chunks.length === 2 && isCanonicalPubKey(chunks[0]) && chunks[1] === ops.OP_CHECKSIG } -function isScriptHashInput (chunks, allowIncomplete) { - chunks = coerceChunks(chunks) +function isScriptHashInput (script, allowIncomplete) { + var chunks = Script.decompile(script) if (chunks.length < 2) return false var lastChunk = chunks[chunks.length - 1] @@ -99,8 +91,8 @@ function isScriptHashInput (chunks, allowIncomplete) { return classifyInput(scriptSigChunks, allowIncomplete) === classifyOutput(redeemScriptChunks) } -function isScriptHashOutput (chunks) { - chunks = coerceChunks(chunks) +function isScriptHashOutput (script) { + var chunks = Script.decompile(script) return chunks.length === 3 && chunks[0] === ops.OP_HASH160 && @@ -111,8 +103,8 @@ function isScriptHashOutput (chunks) { // allowIncomplete is to account for combining signatures // See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197 -function isMultisigInput (chunks, allowIncomplete) { - chunks = coerceChunks(chunks) +function isMultisigInput (script, allowIncomplete) { + var chunks = Script.decompile(script) if (chunks.length < 2) return false if (chunks[0] !== ops.OP_0) return false @@ -125,8 +117,8 @@ function isMultisigInput (chunks, allowIncomplete) { return chunks.slice(1).every(isCanonicalSignature) } -function isMultisigOutput (chunks) { - chunks = coerceChunks(chunks) +function isMultisigOutput (script) { + var chunks = Script.decompile(script) if (chunks.length < 4) return false if (chunks[chunks.length - 1] !== ops.OP_CHECKMULTISIG) return false @@ -150,13 +142,14 @@ function isMultisigOutput (chunks) { return pubKeys.every(isCanonicalPubKey) } -function isNullDataOutput (chunks) { - chunks = coerceChunks(chunks) +function isNullDataOutput (script) { + var chunks = Script.decompile(script) return chunks[0] === ops.OP_RETURN } -function classifyOutput (chunks) { - chunks = coerceChunks(chunks) +function classifyOutput (script) { + var chunks = Script.decompile(script) + if (isPubKeyHashOutput(chunks)) { return 'pubkeyhash' } else if (isScriptHashOutput(chunks)) { @@ -172,8 +165,9 @@ function classifyOutput (chunks) { return 'nonstandard' } -function classifyInput (chunks, allowIncomplete) { - chunks = coerceChunks(chunks) +function classifyInput (script, allowIncomplete) { + var chunks = Script.decompile(script) + if (isPubKeyHashInput(chunks)) { return 'pubkeyhash' } else if (isMultisigInput(chunks, allowIncomplete)) { @@ -237,24 +231,24 @@ function pubKeyHashInput (signature, pubKey) { } // {serialized scriptPubKey script} -function scriptHashInput (scriptSig, scriptPubKeyBuffer) { - scriptSig = coerceChunks(scriptSig) - scriptPubKeyBuffer = coerceBuffer(scriptPubKeyBuffer) +function scriptHashInput (scriptSig, scriptPubKey) { + var scriptSigChunks = Script.decompile(scriptSig) + var serializedScriptPubKey = Script.compile(scriptPubKey) return Script.compile([].concat( - scriptSig, - scriptPubKeyBuffer + scriptSigChunks, + serializedScriptPubKey )) } // OP_0 [signatures ...] function multisigInput (signatures, scriptPubKey) { if (scriptPubKey) { - if (!isMultisigOutput(scriptPubKey)) throw new Error('Expected multisig scriptPubKey') - scriptPubKey = coerceChunks(scriptPubKey) + var chunks = Script.decompile(scriptPubKey) + if (!isMultisigOutput(chunks)) throw new Error('Expected multisig scriptPubKey') - var mOp = scriptPubKey[0] - var nOp = scriptPubKey[scriptPubKey.length - 2] + var mOp = chunks[0] + var nOp = chunks[chunks.length - 2] var m = mOp - (ops.OP_1 - 1) var n = nOp - (ops.OP_1 - 1) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 8683699..cca8b35 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -32,6 +32,12 @@ function extractInput (txIn) { scriptType = prevOutType } + // pre-empt redeemScript decompilation + var redeemScriptChunks + if (redeemScript) { + redeemScriptChunks = Script.decompile(redeemScript) + } + // Extract hashType, pubKeys and signatures var hashType, parsed, pubKeys, signatures @@ -51,7 +57,7 @@ function extractInput (txIn) { signatures = [parsed.signature] if (redeemScript) { - pubKeys = Script.decompile(redeemScript).slice(0, 1) + pubKeys = redeemScriptChunks.slice(0, 1) } break @@ -67,7 +73,7 @@ function extractInput (txIn) { }) if (redeemScript) { - pubKeys = Script.decompile(redeemScript).slice(1, -2) + pubKeys = redeemScriptChunks.slice(1, -2) } break diff --git a/test/scripts.js b/test/scripts.js index bdb9264..f3a8b57 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -267,7 +267,7 @@ describe('Scripts', function () { if (!f.scriptPubKey) return it('returns ' + f.scriptPubKey, function () { - var redeemScript = Script.compile(Script.fromASM(f.redeemScript)) + var redeemScript = Script.fromASM(f.redeemScript) var scriptPubKey = scripts.scriptHashOutput(bcrypto.hash160(redeemScript)) assert.strictEqual(Script.toASM(scriptPubKey), f.scriptPubKey) diff --git a/test/transaction.js b/test/transaction.js index af8639d..cd7f9be 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -22,7 +22,7 @@ describe('Transaction', function () { script = data } else if (txIn.script) { - script = Script.compile(Script.fromASM(txIn.script)) + script = Script.fromASM(txIn.script) } tx.addInput(txHash, txIn.index, txIn.sequence, script) @@ -36,7 +36,7 @@ describe('Transaction', function () { script = data } else if (txOut.script) { - script = Script.compile(Script.fromASM(txOut.script)) + script = Script.fromASM(txOut.script) } tx.addOutput(script, txOut.value) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 8737fdf..57094f4 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -22,14 +22,14 @@ function construct (f, sign) { var prevTxScript if (input.prevTxScript) { - prevTxScript = Script.compile(Script.fromASM(input.prevTxScript)) + prevTxScript = Script.fromASM(input.prevTxScript) } txb.addInput(input.txId, input.vout, input.sequence, prevTxScript) }) f.outputs.forEach(function (output) { - var script = Script.compile(Script.fromASM(output.script)) + var script = Script.fromASM(output.script) txb.addOutput(script, output.value) }) @@ -41,7 +41,7 @@ function construct (f, sign) { var redeemScript if (sign.redeemScript) { - redeemScript = Script.compile(Script.fromASM(sign.redeemScript)) + redeemScript = Script.fromASM(sign.redeemScript) } txb.sign(index, keyPair, redeemScript, sign.hashType) @@ -200,7 +200,7 @@ describe('TransactionBuilder', function () { var redeemScript if (sign.redeemScript) { - redeemScript = Script.compile(Script.fromASM(sign.redeemScript)) + redeemScript = Script.fromASM(sign.redeemScript) } if (!sign.throws) { @@ -262,7 +262,7 @@ describe('TransactionBuilder', function () { var network = NETWORKS[f.network] f.inputs.forEach(function (input, i) { - var redeemScript = Script.compile(Script.fromASM(input.redeemScript)) + var redeemScript = Script.fromASM(input.redeemScript) input.signs.forEach(function (sign) { // rebuild the transaction each-time after the first @@ -309,7 +309,7 @@ describe('TransactionBuilder', function () { txb = TransactionBuilder.fromTransaction(lameTx, network) - var redeemScript = Script.compile(Script.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG')) + var redeemScript = Script.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG') var keyPair = ECPair.fromWIF('91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', network) txb.sign(0, keyPair, redeemScript)