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