move & rename anything to do with signable_scripts
This commit is contained in:
parent
b09cf89f97
commit
3a03691b7d
@ -167,16 +167,91 @@ function InSigner (tx, nIn, opts) {
|
||||
this.nIn = nIn
|
||||
this.publicKeys = []
|
||||
this.signatures = []
|
||||
this.requiredSigs = null
|
||||
this.requiredSigs = 0
|
||||
this.solve(opts)
|
||||
this.extractSig()
|
||||
}
|
||||
|
||||
InSigner.prototype.isFullySigned = function () {
|
||||
return this.requiredSigs !== null && this.requiredSigs === this.signatures.length
|
||||
InSigner.prototype.solve = function (opts) {
|
||||
// Determine scriptPubKey is solvable
|
||||
var scriptPubKey = solveScript(opts.scriptPubKey)
|
||||
if (scriptPubKey.type !== bscript.types.P2SH && ALLOWED_P2SH_SCRIPTS.indexOf(scriptPubKey.type) === -1) {
|
||||
throw new Error('txOut script is non-standard')
|
||||
}
|
||||
|
||||
var solution = scriptPubKey
|
||||
var redeemScript
|
||||
var witnessScript
|
||||
var sigVersion = Transaction.SIG_V0
|
||||
var value = 0
|
||||
|
||||
if (solution.type === bscript.types.P2SH) {
|
||||
var scriptHash = solution.solvedBy
|
||||
// Redeem script must be provided by opts
|
||||
if (!(opts.redeemScript instanceof Buffer)) {
|
||||
throw new Error('Redeem script required to solve utxo')
|
||||
}
|
||||
// Check redeemScript against script-hash
|
||||
if (!scriptHash.equals(bcrypto.hash160(opts.redeemScript))) {
|
||||
throw new Error('Redeem script does not match txOut script hash')
|
||||
}
|
||||
// Prevent non-standard P2SH scripts
|
||||
solution = solveScript(opts.redeemScript)
|
||||
if (!ALLOWED_P2SH_SCRIPTS.indexOf(solution.type)) {
|
||||
throw new Error('Unsupported P2SH script')
|
||||
}
|
||||
redeemScript = solution
|
||||
}
|
||||
|
||||
if (solution.type === bscript.types.P2WPKH) {
|
||||
// txOutValue is required here
|
||||
if (!types.Satoshi(opts.value)) {
|
||||
throw new Error('Value is required for witness-key-hash')
|
||||
}
|
||||
// We set solution to this to avoid work later, since P2WPKH is a special case of P2PKH
|
||||
solution = solveScript(bscript.pubKeyHash.output.encode(solution.solvedBy))
|
||||
sigVersion = Transaction.SIG_V1
|
||||
value = opts.value
|
||||
} else if (solution.type === bscript.types.P2WSH) {
|
||||
var witnessScriptHash = solution.solvedBy
|
||||
// Witness script must be provided by opts
|
||||
if (!(opts.witnessScript instanceof Buffer)) {
|
||||
throw new Error('P2WSH script required to solve utxo')
|
||||
}
|
||||
// txOutValue is required here
|
||||
if (!types.Satoshi(opts.value)) {
|
||||
throw new Error('Value is required for witness-script-hash')
|
||||
}
|
||||
// Check witnessScript against script hash
|
||||
if (!bcrypto.sha256(opts.witnessScript).equals(witnessScriptHash)) {
|
||||
throw new Error('Witness script does not match txOut script hash')
|
||||
}
|
||||
// Prevent non-standard P2WSH scripts
|
||||
solution = solveScript(opts.witnessScript)
|
||||
if (SIGNABLE_SCRIPTS.indexOf(solution.type) === -1) {
|
||||
throw new Error('Witness script is not supported')
|
||||
}
|
||||
witnessScript = solution
|
||||
sigVersion = Transaction.SIG_V1
|
||||
value = opts.value
|
||||
}
|
||||
|
||||
this.requiredSigs = solution.requiredSigs
|
||||
this.scriptPubKey = scriptPubKey
|
||||
this.redeemScript = redeemScript
|
||||
this.witnessScript = witnessScript
|
||||
this.value = value
|
||||
// signScript & sigVersion were added last, they make sign branch free
|
||||
this.sigVersion = sigVersion
|
||||
this.signScript = solution
|
||||
}
|
||||
|
||||
InSigner.prototype.extractStandard = function (solution, chunks, sigVersion) {
|
||||
InSigner.prototype.isFullySigned = function () {
|
||||
return this.requiredSigs !== null && this.signatures.length === this.requiredSigs
|
||||
}
|
||||
|
||||
InSigner.prototype.extractSignableChunks = function (solution, chunks, sigVersion) {
|
||||
// Only SIGNABLE_SCRIPTS can be extracted here
|
||||
var signatures = []
|
||||
var publicKeys = []
|
||||
var decoded
|
||||
@ -222,84 +297,12 @@ InSigner.prototype.extractStandard = function (solution, chunks, sigVersion) {
|
||||
return [signatures, publicKeys]
|
||||
}
|
||||
|
||||
InSigner.prototype.solve = function (opts) {
|
||||
// Determine scriptPubKey is solvable
|
||||
var scriptPubKey = solveScript(opts.scriptPubKey)
|
||||
if (scriptPubKey.type !== bscript.types.P2SH && ALLOWED_P2SH_SCRIPTS.indexOf(scriptPubKey.type) === -1) {
|
||||
throw new Error('txOut script is non-standard')
|
||||
}
|
||||
|
||||
var solution = scriptPubKey
|
||||
var redeemScript
|
||||
var witnessScript
|
||||
var sigVersion = Transaction.SIG_V0
|
||||
var value = 0
|
||||
|
||||
if (solution.type === bscript.types.P2SH) {
|
||||
var scriptHash = solution.solvedBy
|
||||
// Redeem script must be provided by opts
|
||||
if (!(opts.redeemScript instanceof Buffer)) {
|
||||
throw new Error('Redeem script required to solve utxo')
|
||||
}
|
||||
// Check redeemScript against script-hash
|
||||
if (!scriptHash.equals(bcrypto.hash160(opts.redeemScript))) {
|
||||
throw new Error('Redeem script does not match txOut script hash')
|
||||
}
|
||||
// Determine redeemScript is solvable
|
||||
solution = solveScript(opts.redeemScript)
|
||||
if (!ALLOWED_P2SH_SCRIPTS.indexOf(solution.type)) {
|
||||
throw new Error('Unsupported P2SH script')
|
||||
}
|
||||
redeemScript = solution
|
||||
}
|
||||
|
||||
if (solution.type === bscript.types.P2WPKH) {
|
||||
// txOutValue is required here
|
||||
if (!types.Satoshi(opts.value)) {
|
||||
throw new Error('Value is required for witness-key-hash')
|
||||
}
|
||||
// We set solution to this to avoid work later, since P2WPKH is a special case of P2PKH
|
||||
solution = solveScript(bscript.pubKeyHash.output.encode(solution.solvedBy))
|
||||
sigVersion = Transaction.SIG_V1
|
||||
value = opts.value
|
||||
} else if (solution.type === bscript.types.P2WSH) {
|
||||
var witnessScriptHash = solution.solvedBy
|
||||
// Witness script must be provided by opts
|
||||
if (!(opts.witnessScript instanceof Buffer)) {
|
||||
throw new Error('P2WSH script required to solve utxo')
|
||||
}
|
||||
// txOutValue is required here
|
||||
if (!types.Satoshi(opts.value)) {
|
||||
throw new Error('Value is required for witness-script-hash')
|
||||
}
|
||||
// Check witnessScript against script hash
|
||||
if (!bcrypto.sha256(opts.witnessScript).equals(witnessScriptHash)) {
|
||||
throw new Error('Witness script does not match txOut script hash')
|
||||
}
|
||||
solution = solveScript(opts.witnessScript)
|
||||
// Determine if witnessScript is solvable
|
||||
if (SIGNABLE_SCRIPTS.indexOf(solution.type) === -1) {
|
||||
throw new Error('witness script is not supported')
|
||||
}
|
||||
witnessScript = solution
|
||||
sigVersion = Transaction.SIG_V1
|
||||
value = opts.value
|
||||
}
|
||||
|
||||
this.signScript = solution
|
||||
this.scriptPubKey = scriptPubKey
|
||||
this.redeemScript = redeemScript
|
||||
this.witnessScript = witnessScript
|
||||
this.sigVersion = sigVersion
|
||||
this.value = value
|
||||
}
|
||||
|
||||
InSigner.prototype.extractSig = function () {
|
||||
// Attempt decoding of the input scriptSig and witness
|
||||
var input = this.tx.ins[this.nIn]
|
||||
var solution = this.scriptPubKey
|
||||
var extractChunks = []
|
||||
if (solution.canSign) {
|
||||
if (SIGNABLE_SCRIPTS.indexOf(solution.type) !== -1) {
|
||||
extractChunks = evalPushOnly(input.script)
|
||||
}
|
||||
|
||||
@ -311,8 +314,8 @@ InSigner.prototype.extractSig = function () {
|
||||
throw new Error('Redeem script from scriptSig does not match')
|
||||
}
|
||||
solution = this.redeemScript
|
||||
if (solution.canSign) {
|
||||
// We only bother if canSign, otherwise we waste time
|
||||
if (SIGNABLE_SCRIPTS.indexOf(solution.canSign) !== -1) {
|
||||
// only do this if we can sign, otherwise we waste CPU
|
||||
extractChunks = evalPushOnly(p2sh.redeemScriptSig)
|
||||
}
|
||||
}
|
||||
@ -338,42 +341,44 @@ InSigner.prototype.extractSig = function () {
|
||||
}
|
||||
|
||||
if (extractChunks.length > 0) {
|
||||
[this.signatures, this.publicKeys] = this.extractStandard(solution, extractChunks, this.sigVersion)
|
||||
[this.signatures, this.publicKeys] = this.extractSignableChunks(solution, extractChunks, this.sigVersion)
|
||||
}
|
||||
}
|
||||
|
||||
function signStandard (tx, nIn, txOutValue, signatures, publicKeys, key, solution, sigHashType, sigVersion) {
|
||||
function signSignable (tx, nIn, txOutValue, signatures, publicKeys, key, solution, sigHashType, sigVersion) {
|
||||
// Todo, skip if already signed
|
||||
// Only SIGNABLE_SCRIPTS can be signed here
|
||||
var didSign = false
|
||||
var keyBuffer = key.getPublicKeyBuffer()
|
||||
if (solution.type === bscript.types.P2PK) {
|
||||
if (bufferEquals(keyBuffer, solution.solvedBy)) {
|
||||
signatures = [calculateSignature(tx, nIn, key, solution.script, sigHashType, sigVersion, txOutValue)]
|
||||
publicKeys = [keyBuffer]
|
||||
didSign = true
|
||||
} else {
|
||||
throw new Error('Signing input with wrong private key')
|
||||
}
|
||||
} else if (solution.type === bscript.types.P2PKH) {
|
||||
if (bufferEquals(bcrypto.hash160(keyBuffer), solution.solvedBy)) {
|
||||
signatures = [calculateSignature(tx, nIn, key, solution.script, sigHashType, sigVersion, txOutValue)]
|
||||
publicKeys = [keyBuffer]
|
||||
didSign = true
|
||||
} else {
|
||||
throw new Error('Signing input with wrong private key')
|
||||
}
|
||||
} else if (solution.type === bscript.types.MULTISIG) {
|
||||
var match = false
|
||||
for (var i = 0, keyLen = solution.solvedBy.pubKeys.length; i < keyLen; i++) {
|
||||
publicKeys[i] = solution.solvedBy.pubKeys[i]
|
||||
if (bufferEquals(keyBuffer, publicKeys[i])) {
|
||||
didSign = true
|
||||
match = true
|
||||
signatures[i] = calculateSignature(tx, nIn, key, solution.script, sigHashType, sigVersion, txOutValue)
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
throw new Error('Signing input with wrong private key')
|
||||
}
|
||||
} else {
|
||||
throw new Error('signStandard can only sign SIGNABLE_SCRIPTS')
|
||||
}
|
||||
|
||||
if (!didSign) {
|
||||
throw new Error('Signing input with wrong private key')
|
||||
}
|
||||
|
||||
return [signatures, publicKeys]
|
||||
}
|
||||
|
||||
@ -384,14 +389,11 @@ function signStandard (tx, nIn, txOutValue, signatures, publicKeys, key, solutio
|
||||
* @returns {{type, script, canSign, solvedBy, requiredSigs}|*}
|
||||
*/
|
||||
InSigner.prototype.sign = function (key, sigHashType) {
|
||||
sigHashType = sigHashType || Transaction.SIGHASH_ALL
|
||||
var solution = this.signScript;
|
||||
// Attempt to solve the txOut script
|
||||
|
||||
[this.signatures, this.publicKeys] = signStandard(this.tx, this.nIn, this.value, this.signatures, this.publicKeys, key, solution, sigHashType, this.sigVersion)
|
||||
sigHashType = sigHashType || Transaction.SIGHASH_ALL;
|
||||
[this.signatures, this.publicKeys] = signSignable(this.tx, this.nIn, this.value, this.signatures, this.publicKeys, key, this.signScript, sigHashType, this.sigVersion)
|
||||
this.requiredSigs = this.publicKeys.length
|
||||
|
||||
return solution
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@ -403,8 +405,8 @@ InSigner.prototype.sign = function (key, sigHashType) {
|
||||
* @param publicKeys
|
||||
* @returns {Array}
|
||||
*/
|
||||
function serializeStandard (outputType, signatures, publicKeys) {
|
||||
// When adding a new script type, edit here
|
||||
function serializeSignableChunks (outputType, signatures, publicKeys) {
|
||||
// Only SIGNABLE_SCRIPTS can be serialized here
|
||||
var chunks = []
|
||||
switch (outputType) {
|
||||
case bscript.types.P2PK:
|
||||
@ -438,7 +440,7 @@ InSigner.prototype.serializeSigData = function () {
|
||||
var witnessChunks = []
|
||||
var type = this.scriptPubKey.type
|
||||
if (this.scriptPubKey.canSign) {
|
||||
scriptChunks = serializeStandard(type, this.signatures, this.publicKeys)
|
||||
scriptChunks = serializeSignableChunks(type, this.signatures, this.publicKeys)
|
||||
}
|
||||
|
||||
var p2sh = false
|
||||
@ -446,17 +448,17 @@ InSigner.prototype.serializeSigData = function () {
|
||||
p2sh = true
|
||||
type = this.redeemScript.type
|
||||
if (this.redeemScript.canSign) {
|
||||
scriptChunks = serializeStandard(type, this.signatures, this.publicKeys)
|
||||
scriptChunks = serializeSignableChunks(type, this.signatures, this.publicKeys)
|
||||
}
|
||||
}
|
||||
|
||||
if (type === bscript.types.P2WPKH) {
|
||||
witnessChunks = serializeStandard(bscript.types.P2PKH, this.signatures, this.publicKeys)
|
||||
witnessChunks = serializeSignableChunks(bscript.types.P2PKH, this.signatures, this.publicKeys)
|
||||
} else if (type === bscript.types.P2WSH) {
|
||||
type = this.witnessScript.type
|
||||
if (this.witnessScript.canSign) {
|
||||
scriptChunks = []
|
||||
witnessChunks = serializeStandard(type, this.signatures, this.publicKeys)
|
||||
witnessChunks = serializeSignableChunks(type, this.signatures, this.publicKeys)
|
||||
witnessChunks.push(this.witnessScript.script);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user