2015-08-22 11:54:00 +10:00
|
|
|
var bip66 = require('bip66')
|
2015-08-14 11:16:17 +10:00
|
|
|
var bufferutils = require('./bufferutils')
|
2015-08-11 17:01:47 +10:00
|
|
|
var typeforce = require('typeforce')
|
|
|
|
var types = require('./types')
|
2014-06-24 17:32:23 +10:00
|
|
|
|
2016-06-08 17:00:37 -05:00
|
|
|
var OPS = require('./opcodes.json')
|
2015-10-02 12:59:30 +10:00
|
|
|
var REVERSE_OPS = (function () {
|
|
|
|
var result = {}
|
|
|
|
for (var op in OPS) {
|
|
|
|
var code = OPS[op]
|
|
|
|
result[code] = op
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
})()
|
2015-08-14 11:16:17 +10:00
|
|
|
|
2015-11-18 22:04:21 -08:00
|
|
|
var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1
|
2015-10-02 13:00:00 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
function compile (chunks) {
|
|
|
|
// TODO: remove me
|
2015-11-26 12:07:04 +11:00
|
|
|
if (Buffer.isBuffer(chunks)) return chunks
|
2015-08-14 11:16:17 +10:00
|
|
|
|
|
|
|
typeforce(types.Array, chunks)
|
|
|
|
|
|
|
|
var bufferSize = chunks.reduce(function (accum, chunk) {
|
|
|
|
// data chunk
|
|
|
|
if (Buffer.isBuffer(chunk)) {
|
2016-09-29 13:48:17 +10:00
|
|
|
// adhere to BIP62.3, minimal push policy
|
|
|
|
if (chunk.length === 1 && chunk[0] >= 1 && chunk[0] <= 16) {
|
|
|
|
return accum + 1
|
|
|
|
}
|
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return accum + bufferutils.pushDataSize(chunk.length) + chunk.length
|
|
|
|
}
|
|
|
|
|
|
|
|
// opcode
|
|
|
|
return accum + 1
|
|
|
|
}, 0.0)
|
|
|
|
|
|
|
|
var buffer = new Buffer(bufferSize)
|
|
|
|
var offset = 0
|
|
|
|
|
|
|
|
chunks.forEach(function (chunk) {
|
|
|
|
// data chunk
|
|
|
|
if (Buffer.isBuffer(chunk)) {
|
2016-09-29 13:48:17 +10:00
|
|
|
// adhere to BIP62.3, minimal push policy
|
|
|
|
if (chunk.length === 1 && chunk[0] >= 1 && chunk[0] <= 16) {
|
|
|
|
var opcode = OP_INT_BASE + chunk[0]
|
|
|
|
buffer.writeUInt8(opcode, offset)
|
|
|
|
offset += 1
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)
|
|
|
|
|
|
|
|
chunk.copy(buffer, offset)
|
|
|
|
offset += chunk.length
|
|
|
|
|
|
|
|
// opcode
|
|
|
|
} else {
|
|
|
|
buffer.writeUInt8(chunk, offset)
|
|
|
|
offset += 1
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if (offset !== buffer.length) throw new Error('Could not decode chunks')
|
|
|
|
return buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
function decompile (buffer) {
|
|
|
|
// TODO: remove me
|
|
|
|
if (types.Array(buffer)) return buffer
|
|
|
|
|
|
|
|
typeforce(types.Buffer, buffer)
|
|
|
|
|
|
|
|
var chunks = []
|
|
|
|
var i = 0
|
|
|
|
|
|
|
|
while (i < buffer.length) {
|
2015-08-25 18:08:32 +10:00
|
|
|
var opcode = buffer[i]
|
2015-08-14 11:16:17 +10:00
|
|
|
|
|
|
|
// data chunk
|
|
|
|
if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) {
|
|
|
|
var d = bufferutils.readPushDataInt(buffer, i)
|
|
|
|
|
|
|
|
// did reading a pushDataInt fail? empty script
|
|
|
|
if (d === null) return []
|
|
|
|
i += d.size
|
|
|
|
|
|
|
|
// attempt to read too much data? empty script
|
|
|
|
if (i + d.number > buffer.length) return []
|
|
|
|
|
|
|
|
var data = buffer.slice(i, i + d.number)
|
|
|
|
i += d.number
|
|
|
|
|
|
|
|
chunks.push(data)
|
|
|
|
|
|
|
|
// opcode
|
|
|
|
} else {
|
|
|
|
chunks.push(opcode)
|
|
|
|
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return chunks
|
|
|
|
}
|
2014-06-12 21:14:22 +10:00
|
|
|
|
2016-09-28 08:44:21 +10:00
|
|
|
function toASM (chunks) {
|
|
|
|
if (Buffer.isBuffer(chunks)) {
|
|
|
|
chunks = decompile(chunks)
|
|
|
|
}
|
|
|
|
|
|
|
|
return chunks.map(function (chunk) {
|
|
|
|
// data?
|
|
|
|
if (Buffer.isBuffer(chunk)) return chunk.toString('hex')
|
|
|
|
|
|
|
|
// opcode!
|
|
|
|
return REVERSE_OPS[chunk]
|
|
|
|
}).join(' ')
|
|
|
|
}
|
|
|
|
|
|
|
|
function fromASM (asm) {
|
|
|
|
typeforce(types.String, asm)
|
|
|
|
|
|
|
|
return compile(asm.split(' ').map(function (chunkStr) {
|
|
|
|
// opcode?
|
|
|
|
if (OPS[chunkStr] !== undefined) return OPS[chunkStr]
|
|
|
|
|
|
|
|
// data!
|
|
|
|
return new Buffer(chunkStr, 'hex')
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2015-02-23 10:36:57 +11:00
|
|
|
function isCanonicalPubKey (buffer) {
|
2014-06-24 17:32:23 +10:00
|
|
|
if (!Buffer.isBuffer(buffer)) return false
|
2015-08-22 12:31:32 +10:00
|
|
|
if (buffer.length < 33) return false
|
|
|
|
|
|
|
|
switch (buffer[0]) {
|
|
|
|
case 0x02:
|
|
|
|
case 0x03:
|
|
|
|
return buffer.length === 33
|
|
|
|
case 0x04:
|
|
|
|
return buffer.length === 65
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2015-08-22 12:31:32 +10:00
|
|
|
return false
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2015-08-22 12:31:00 +10:00
|
|
|
function isDefinedHashType (hashType) {
|
|
|
|
var hashTypeMod = hashType & ~0x80
|
|
|
|
|
|
|
|
// return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
|
|
|
|
return hashTypeMod > 0x00 && hashTypeMod < 0x04
|
|
|
|
}
|
|
|
|
|
2016-09-28 08:44:21 +10:00
|
|
|
function isCanonicalSignature (buffer) {
|
|
|
|
if (!Buffer.isBuffer(buffer)) return false
|
|
|
|
if (!isDefinedHashType(buffer[buffer.length - 1])) return false
|
|
|
|
|
|
|
|
return bip66.check(buffer.slice(0, -1))
|
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isPubKeyHashInput (script) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-18 10:17:04 +10:00
|
|
|
|
|
|
|
return chunks.length === 2 &&
|
|
|
|
isCanonicalSignature(chunks[0]) &&
|
|
|
|
isCanonicalPubKey(chunks[1])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isPubKeyHashOutput (script) {
|
2015-09-29 18:55:33 +10:00
|
|
|
var buffer = compile(script)
|
|
|
|
|
|
|
|
return buffer.length === 25 &&
|
|
|
|
buffer[0] === OPS.OP_DUP &&
|
|
|
|
buffer[1] === OPS.OP_HASH160 &&
|
|
|
|
buffer[2] === 0x14 &&
|
|
|
|
buffer[23] === OPS.OP_EQUALVERIFY &&
|
|
|
|
buffer[24] === OPS.OP_CHECKSIG
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isPubKeyInput (script) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-07 16:30:24 +10:00
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
return chunks.length === 1 &&
|
|
|
|
isCanonicalSignature(chunks[0])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isPubKeyOutput (script) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-18 10:17:04 +10:00
|
|
|
|
|
|
|
return chunks.length === 2 &&
|
|
|
|
isCanonicalPubKey(chunks[0]) &&
|
2015-08-14 11:16:17 +10:00
|
|
|
chunks[1] === OPS.OP_CHECKSIG
|
2015-08-18 10:17:04 +10:00
|
|
|
}
|
2015-08-07 16:30:24 +10:00
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isScriptHashInput (script, allowIncomplete) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-18 10:17:04 +10:00
|
|
|
if (chunks.length < 2) return false
|
2014-06-24 17:32:23 +10:00
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
var lastChunk = chunks[chunks.length - 1]
|
2014-06-24 17:32:23 +10:00
|
|
|
if (!Buffer.isBuffer(lastChunk)) return false
|
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
var scriptSigChunks = chunks.slice(0, -1)
|
2015-08-14 11:16:17 +10:00
|
|
|
var redeemScriptChunks = decompile(lastChunk)
|
2015-02-16 02:39:57 +11:00
|
|
|
|
2015-03-04 21:00:07 +11:00
|
|
|
// is redeemScript a valid script?
|
2015-08-18 10:17:04 +10:00
|
|
|
if (redeemScriptChunks.length === 0) return false
|
2014-06-24 17:32:23 +10:00
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
return classifyInput(scriptSigChunks, allowIncomplete) === classifyOutput(redeemScriptChunks)
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isScriptHashOutput (script) {
|
2015-09-29 18:55:33 +10:00
|
|
|
var buffer = compile(script)
|
2015-08-07 16:30:24 +10:00
|
|
|
|
2015-09-29 18:55:33 +10:00
|
|
|
return buffer.length === 23 &&
|
|
|
|
buffer[0] === OPS.OP_HASH160 &&
|
|
|
|
buffer[1] === 0x14 &&
|
|
|
|
buffer[22] === OPS.OP_EQUAL
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2016-07-12 01:37:59 +10:00
|
|
|
function isWitnessPubKeyHashOutput (script) {
|
|
|
|
var buffer = compile(script)
|
|
|
|
|
|
|
|
return buffer.length === 22 &&
|
2016-07-12 11:42:01 +10:00
|
|
|
buffer[0] === OPS.OP_0 &&
|
|
|
|
buffer[1] === 0x14
|
2016-07-12 01:37:59 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
function isWitnessScriptHashOutput (script) {
|
|
|
|
var buffer = compile(script)
|
|
|
|
|
|
|
|
return buffer.length === 34 &&
|
2016-07-12 11:42:01 +10:00
|
|
|
buffer[0] === OPS.OP_0 &&
|
|
|
|
buffer[1] === 0x20
|
2016-07-12 01:37:59 +10:00
|
|
|
}
|
|
|
|
|
2015-02-11 14:01:20 +11:00
|
|
|
// allowIncomplete is to account for combining signatures
|
|
|
|
// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197
|
2015-08-14 10:31:48 +10:00
|
|
|
function isMultisigInput (script, allowIncomplete) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-18 10:17:04 +10:00
|
|
|
if (chunks.length < 2) return false
|
2015-08-14 11:16:17 +10:00
|
|
|
if (chunks[0] !== OPS.OP_0) return false
|
2015-02-11 14:01:20 +11:00
|
|
|
|
|
|
|
if (allowIncomplete) {
|
2015-08-18 10:17:04 +10:00
|
|
|
return chunks.slice(1).every(function (chunk) {
|
2015-08-14 11:16:17 +10:00
|
|
|
return chunk === OPS.OP_0 || isCanonicalSignature(chunk)
|
2015-02-11 14:01:20 +11:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
return chunks.slice(1).every(isCanonicalSignature)
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isMultisigOutput (script) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-18 10:17:04 +10:00
|
|
|
if (chunks.length < 4) return false
|
2015-08-14 11:16:17 +10:00
|
|
|
if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false
|
2014-06-24 17:32:23 +10:00
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
var mOp = chunks[0]
|
|
|
|
var nOp = chunks[chunks.length - 2]
|
2015-10-02 13:00:00 +10:00
|
|
|
|
|
|
|
if (!types.Number(mOp)) return false
|
2015-10-02 12:51:34 +10:00
|
|
|
if (!types.Number(nOp)) return false
|
2014-06-26 16:22:29 +10:00
|
|
|
|
2015-10-02 13:00:00 +10:00
|
|
|
var m = mOp - OP_INT_BASE
|
|
|
|
var n = nOp - OP_INT_BASE
|
|
|
|
|
|
|
|
// 0 < m <= n <= 16
|
|
|
|
if (m <= 0) return false
|
|
|
|
if (m > n) return false
|
|
|
|
if (n > 16) return false
|
2015-10-02 13:02:03 +10:00
|
|
|
if (n !== chunks.length - 3) return false
|
2014-06-24 17:32:23 +10:00
|
|
|
|
2015-10-02 13:02:03 +10:00
|
|
|
return chunks.slice(1, -2).every(isCanonicalPubKey)
|
2014-06-24 17:32:23 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function isNullDataOutput (script) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
|
|
|
return chunks[0] === OPS.OP_RETURN
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function classifyOutput (script) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-14 10:31:48 +10:00
|
|
|
|
2016-07-12 01:37:59 +10:00
|
|
|
if (isWitnessPubKeyHashOutput(chunks)) {
|
|
|
|
return 'witnesspubkeyhash'
|
|
|
|
} else if (isWitnessScriptHashOutput(chunks)) {
|
|
|
|
return 'witnessscripthash'
|
|
|
|
} else if (isPubKeyHashOutput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'pubkeyhash'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isScriptHashOutput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'scripthash'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isMultisigOutput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'multisig'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isPubKeyOutput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'pubkey'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isNullDataOutput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'nulldata'
|
|
|
|
}
|
2014-10-13 18:53:07 +11:00
|
|
|
|
|
|
|
return 'nonstandard'
|
2014-10-13 18:38:54 +11:00
|
|
|
}
|
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
function classifyInput (script, allowIncomplete) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(script)
|
2015-08-14 10:31:48 +10:00
|
|
|
|
2015-08-18 10:17:04 +10:00
|
|
|
if (isPubKeyHashInput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'pubkeyhash'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isMultisigInput(chunks, allowIncomplete)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'multisig'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isScriptHashInput(chunks, allowIncomplete)) {
|
2015-02-11 14:01:20 +11:00
|
|
|
return 'scripthash'
|
2015-08-18 10:17:04 +10:00
|
|
|
} else if (isPubKeyInput(chunks)) {
|
2014-10-13 18:38:54 +11:00
|
|
|
return 'pubkey'
|
|
|
|
}
|
2014-10-13 18:53:07 +11:00
|
|
|
|
|
|
|
return 'nonstandard'
|
2014-10-13 18:38:54 +11:00
|
|
|
}
|
|
|
|
|
2014-06-12 21:14:22 +10:00
|
|
|
// Standard Script Templates
|
|
|
|
// {pubKey} OP_CHECKSIG
|
2015-02-23 10:36:57 +11:00
|
|
|
function pubKeyOutput (pubKey) {
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([pubKey, OPS.OP_CHECKSIG])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
|
2015-08-18 10:17:04 +10:00
|
|
|
function pubKeyHashOutput (pubKeyHash) {
|
2015-08-18 09:05:23 +10:00
|
|
|
typeforce(types.Hash160bit, pubKeyHash)
|
2015-08-18 10:17:04 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([OPS.OP_DUP, OPS.OP_HASH160, pubKeyHash, OPS.OP_EQUALVERIFY, OPS.OP_CHECKSIG])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// OP_HASH160 {scriptHash} OP_EQUAL
|
2015-08-18 10:17:04 +10:00
|
|
|
function scriptHashOutput (scriptHash) {
|
2015-08-18 09:05:23 +10:00
|
|
|
typeforce(types.Hash160bit, scriptHash)
|
2015-08-18 10:17:04 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// m [pubKeys ...] n OP_CHECKMULTISIG
|
2015-02-23 10:36:57 +11:00
|
|
|
function multisigOutput (m, pubKeys) {
|
2015-08-11 17:01:47 +10:00
|
|
|
typeforce(types.tuple(types.Number, [types.Buffer]), arguments)
|
2014-09-15 14:21:01 +10:00
|
|
|
|
2014-06-12 21:14:22 +10:00
|
|
|
var n = pubKeys.length
|
2015-08-11 17:07:13 +10:00
|
|
|
if (n < m) throw new Error('Not enough pubKeys provided')
|
2014-06-12 21:14:22 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([].concat(
|
2015-10-02 13:00:00 +10:00
|
|
|
OP_INT_BASE + m,
|
2015-03-02 16:48:36 +11:00
|
|
|
pubKeys,
|
2015-10-02 13:00:00 +10:00
|
|
|
OP_INT_BASE + n,
|
2015-08-14 11:16:17 +10:00
|
|
|
OPS.OP_CHECKMULTISIG
|
2015-08-18 10:17:04 +10:00
|
|
|
))
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2016-07-12 01:37:59 +10:00
|
|
|
// OP_0 {pubKeyHash}
|
|
|
|
function witnessPubKeyHashOutput (pubKeyHash) {
|
|
|
|
typeforce(types.Hash160bit, pubKeyHash)
|
|
|
|
|
|
|
|
return compile([OPS.OP_0, pubKeyHash])
|
|
|
|
}
|
|
|
|
|
|
|
|
// OP_0 {scriptHash}
|
|
|
|
function witnessScriptHashOutput (scriptHash) {
|
|
|
|
typeforce(types.Hash256bit, scriptHash)
|
|
|
|
|
|
|
|
return compile([OPS.OP_0, scriptHash])
|
|
|
|
}
|
|
|
|
|
2014-06-12 21:14:22 +10:00
|
|
|
// {signature}
|
2015-02-23 10:36:57 +11:00
|
|
|
function pubKeyInput (signature) {
|
2015-08-11 17:01:47 +10:00
|
|
|
typeforce(types.Buffer, signature)
|
2014-06-12 21:14:22 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([signature])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// {signature} {pubKey}
|
2015-02-23 10:36:57 +11:00
|
|
|
function pubKeyHashInput (signature, pubKey) {
|
2015-08-11 17:01:47 +10:00
|
|
|
typeforce(types.tuple(types.Buffer, types.Buffer), arguments)
|
2014-06-12 21:14:22 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([signature, pubKey])
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// <scriptSig> {serialized scriptPubKey script}
|
2015-08-14 10:31:48 +10:00
|
|
|
function scriptHashInput (scriptSig, scriptPubKey) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var scriptSigChunks = decompile(scriptSig)
|
|
|
|
var serializedScriptPubKey = compile(scriptPubKey)
|
2015-08-18 10:17:04 +10:00
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([].concat(
|
2015-08-14 10:31:48 +10:00
|
|
|
scriptSigChunks,
|
|
|
|
serializedScriptPubKey
|
2015-08-18 10:17:04 +10:00
|
|
|
))
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2016-07-12 01:37:59 +10:00
|
|
|
// <scriptSig> {serialized scriptPubKey script}
|
|
|
|
function witnessScriptHashInput (scriptSig, scriptPubKey) {
|
|
|
|
return scriptHashInput(scriptSig, scriptPubKey)
|
|
|
|
}
|
|
|
|
|
2014-06-12 21:14:22 +10:00
|
|
|
// OP_0 [signatures ...]
|
2015-02-23 10:36:57 +11:00
|
|
|
function multisigInput (signatures, scriptPubKey) {
|
2014-06-12 21:14:22 +10:00
|
|
|
if (scriptPubKey) {
|
2015-08-14 11:16:17 +10:00
|
|
|
var chunks = decompile(scriptPubKey)
|
2015-08-14 10:31:48 +10:00
|
|
|
if (!isMultisigOutput(chunks)) throw new Error('Expected multisig scriptPubKey')
|
2014-06-12 21:14:22 +10:00
|
|
|
|
2015-08-14 10:31:48 +10:00
|
|
|
var mOp = chunks[0]
|
|
|
|
var nOp = chunks[chunks.length - 2]
|
2015-10-02 13:00:00 +10:00
|
|
|
var m = mOp - OP_INT_BASE
|
|
|
|
var n = nOp - OP_INT_BASE
|
2014-08-30 13:02:02 +10:00
|
|
|
|
2015-08-11 17:07:13 +10:00
|
|
|
if (signatures.length < m) throw new Error('Not enough signatures provided')
|
|
|
|
if (signatures.length > n) throw new Error('Too many signatures provided')
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([].concat(OPS.OP_0, signatures))
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|
|
|
|
|
2015-02-23 10:36:57 +11:00
|
|
|
function nullDataOutput (data) {
|
2015-08-14 11:16:17 +10:00
|
|
|
return compile([OPS.OP_RETURN, data])
|
2014-10-19 12:29:40 +11:00
|
|
|
}
|
|
|
|
|
2014-06-12 21:14:22 +10:00
|
|
|
module.exports = {
|
2015-08-14 11:16:17 +10:00
|
|
|
compile: compile,
|
|
|
|
decompile: decompile,
|
|
|
|
fromASM: fromASM,
|
|
|
|
toASM: toASM,
|
|
|
|
|
2016-01-05 02:11:48 +11:00
|
|
|
number: require('./script_number'),
|
|
|
|
|
2014-11-28 12:50:37 +11:00
|
|
|
isCanonicalPubKey: isCanonicalPubKey,
|
|
|
|
isCanonicalSignature: isCanonicalSignature,
|
2015-08-22 12:31:00 +10:00
|
|
|
isDefinedHashType: isDefinedHashType,
|
2014-11-28 12:50:37 +11:00
|
|
|
isPubKeyHashInput: isPubKeyHashInput,
|
|
|
|
isPubKeyHashOutput: isPubKeyHashOutput,
|
|
|
|
isPubKeyInput: isPubKeyInput,
|
|
|
|
isPubKeyOutput: isPubKeyOutput,
|
|
|
|
isScriptHashInput: isScriptHashInput,
|
|
|
|
isScriptHashOutput: isScriptHashOutput,
|
2016-07-12 01:37:59 +10:00
|
|
|
isWitnessPubKeyHashOutput: isWitnessPubKeyHashOutput,
|
|
|
|
isWitnessScriptHashOutput: isWitnessScriptHashOutput,
|
2014-11-28 12:50:37 +11:00
|
|
|
isMultisigInput: isMultisigInput,
|
|
|
|
isMultisigOutput: isMultisigOutput,
|
|
|
|
isNullDataOutput: isNullDataOutput,
|
2016-07-12 01:37:59 +10:00
|
|
|
|
2014-06-13 09:58:52 +10:00
|
|
|
classifyOutput: classifyOutput,
|
2014-11-28 12:50:37 +11:00
|
|
|
classifyInput: classifyInput,
|
|
|
|
pubKeyOutput: pubKeyOutput,
|
2014-06-13 09:58:52 +10:00
|
|
|
pubKeyHashOutput: pubKeyHashOutput,
|
2014-11-28 12:50:37 +11:00
|
|
|
scriptHashOutput: scriptHashOutput,
|
2016-07-12 01:37:59 +10:00
|
|
|
witnessPubKeyHashOutput: witnessPubKeyHashOutput,
|
|
|
|
witnessScriptHashInput: witnessScriptHashInput,
|
|
|
|
witnessScriptHashOutput: witnessScriptHashOutput,
|
|
|
|
|
2014-11-28 12:50:37 +11:00
|
|
|
multisigOutput: multisigOutput,
|
2014-06-13 09:58:52 +10:00
|
|
|
pubKeyInput: pubKeyInput,
|
2014-11-28 12:50:37 +11:00
|
|
|
pubKeyHashInput: pubKeyHashInput,
|
2014-06-13 09:58:52 +10:00
|
|
|
scriptHashInput: scriptHashInput,
|
2014-11-28 12:50:37 +11:00
|
|
|
multisigInput: multisigInput,
|
|
|
|
nullDataOutput: nullDataOutput
|
2014-06-12 21:14:22 +10:00
|
|
|
}
|