TxBuilder: remove initialized field from signature inputs
This commit is contained in:
parent
fd2311bda4
commit
3a371fccec
2 changed files with 58 additions and 65 deletions
|
@ -33,21 +33,32 @@ function extractInput(txIn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract hashType, pubKeys and signatures
|
// Extract hashType, pubKeys and signatures
|
||||||
var hashType, initialized, parsed, pubKeys, signatures
|
var hashType, parsed, pubKeys, signatures
|
||||||
|
|
||||||
switch (scriptType) {
|
switch (scriptType) {
|
||||||
case 'pubkeyhash':
|
case 'pubkeyhash': {
|
||||||
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
|
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
|
||||||
hashType = parsed.hashType
|
hashType = parsed.hashType
|
||||||
pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])]
|
pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])]
|
||||||
signatures = [parsed.signature]
|
signatures = [parsed.signature]
|
||||||
|
|
||||||
initialized = true
|
|
||||||
prevOutScript = pubKeys[0].getAddress().toOutputScript()
|
prevOutScript = pubKeys[0].getAddress().toOutputScript()
|
||||||
|
|
||||||
break
|
break
|
||||||
|
}
|
||||||
|
|
||||||
case 'multisig':
|
case 'pubkey': {
|
||||||
|
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
|
||||||
|
hashType = parsed.hashType
|
||||||
|
signatures = [parsed.signature]
|
||||||
|
|
||||||
|
if (redeemScript) {
|
||||||
|
pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'multisig': {
|
||||||
signatures = scriptSig.chunks.slice(1).map(function(chunk) {
|
signatures = scriptSig.chunks.slice(1).map(function(chunk) {
|
||||||
if (chunk === ops.OP_0) return chunk
|
if (chunk === ops.OP_0) return chunk
|
||||||
|
|
||||||
|
@ -62,31 +73,11 @@ function extractInput(txIn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
|
}
|
||||||
case 'pubkey':
|
|
||||||
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
|
|
||||||
hashType = parsed.hashType
|
|
||||||
signatures = [parsed.signature]
|
|
||||||
|
|
||||||
initialized = true
|
|
||||||
|
|
||||||
if (redeemScript) {
|
|
||||||
pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (redeemScript) {
|
|
||||||
initialized = true
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hashType: hashType,
|
hashType: hashType,
|
||||||
initialized: initialized,
|
|
||||||
prevOutScript: prevOutScript,
|
prevOutScript: prevOutScript,
|
||||||
prevOutType: prevOutType,
|
prevOutType: prevOutType,
|
||||||
pubKeys: pubKeys,
|
pubKeys: pubKeys,
|
||||||
|
@ -222,38 +213,40 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
|
||||||
var scriptSig
|
var scriptSig
|
||||||
|
|
||||||
if (!allowIncomplete) {
|
if (!allowIncomplete) {
|
||||||
assert(input.initialized, 'Transaction is not complete')
|
assert(!!scriptType, 'Transaction is not complete')
|
||||||
assert(scriptType in canSignTypes, scriptType + ' not supported')
|
assert(scriptType in canSignTypes, scriptType + ' not supported')
|
||||||
assert(input.signatures, 'Transaction is missing signatures')
|
assert(input.signatures, 'Transaction is missing signatures')
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (scriptType) {
|
if (input.signatures) {
|
||||||
case 'pubkeyhash':
|
switch (scriptType) {
|
||||||
var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
|
case 'pubkeyhash':
|
||||||
scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0])
|
var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
|
||||||
break
|
scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0])
|
||||||
|
break
|
||||||
|
|
||||||
case 'multisig':
|
case 'multisig':
|
||||||
// Array.prototype.map is sparse-compatible
|
// Array.prototype.map is sparse-compatible
|
||||||
var msSignatures = input.signatures.map(function(signature) {
|
var msSignatures = input.signatures.map(function(signature) {
|
||||||
return signature.toScriptSignature(input.hashType)
|
return signature.toScriptSignature(input.hashType)
|
||||||
})
|
})
|
||||||
|
|
||||||
// fill in blanks with OP_0
|
// fill in blanks with OP_0
|
||||||
for (var i = 0; i < msSignatures.length; ++i) {
|
for (var i = 0; i < msSignatures.length; ++i) {
|
||||||
if (msSignatures[i]) continue
|
if (msSignatures[i]) continue
|
||||||
|
|
||||||
msSignatures[i] = ops.OP_0
|
msSignatures[i] = ops.OP_0
|
||||||
}
|
}
|
||||||
|
|
||||||
var redeemScript = allowIncomplete ? undefined : input.redeemScript
|
var redeemScript = allowIncomplete ? undefined : input.redeemScript
|
||||||
scriptSig = scripts.multisigInput(signatures, redeemScript)
|
scriptSig = scripts.multisigInput(msSignatures, redeemScript)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'pubkey':
|
case 'pubkey':
|
||||||
var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
|
var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
|
||||||
scriptSig = scripts.pubKeyInput(pkSignature)
|
scriptSig = scripts.pubKeyInput(pkSignature)
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we built a scriptSig, wrap as scriptHash if necessary
|
// if we built a scriptSig, wrap as scriptHash if necessary
|
||||||
|
@ -277,18 +270,19 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
|
||||||
assert.equal(input.hashType, hashType, 'Inconsistent hashType')
|
assert.equal(input.hashType, hashType, 'Inconsistent hashType')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var initialized = input.prevOutScript &&
|
||||||
|
input.prevOutType &&
|
||||||
|
input.hashType &&
|
||||||
|
input.pubKeys &&
|
||||||
|
input.signatures
|
||||||
|
|
||||||
// are we already initialized?
|
// are we already initialized?
|
||||||
if (input.initialized) {
|
if (initialized) {
|
||||||
// redeemScript only needed to initialize, but if provided again, enforce consistency
|
// redeemScript only needed to initialize, but if provided again, enforce consistency
|
||||||
if (redeemScript) {
|
if (redeemScript) {
|
||||||
assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
|
assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
|
||||||
}
|
}
|
||||||
|
|
||||||
// if signatures already exist, enforce multisig scriptType
|
|
||||||
if (input.signatures.length > 0) {
|
|
||||||
assert.equal(input.scriptType, 'multisig', input.scriptType + ' doesn\'t support multiple signatures')
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize it
|
// initialize it
|
||||||
} else {
|
} else {
|
||||||
if (redeemScript) {
|
if (redeemScript) {
|
||||||
|
@ -344,26 +338,24 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
|
||||||
}
|
}
|
||||||
|
|
||||||
input.hashType = hashType
|
input.hashType = hashType
|
||||||
input.initialized = true
|
|
||||||
input.signatures = input.signatures || []
|
input.signatures = input.signatures || []
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we know how to sign this?
|
// do we know how to sign this?
|
||||||
assert(input.scriptType in canSignTypes, input.scriptType + ' not supported')
|
assert(input.scriptType in canSignTypes, input.scriptType + ' not supported')
|
||||||
|
|
||||||
var signatureScript = input.redeemScript || input.prevOutScript
|
// enforce in order signing of public keys
|
||||||
var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType)
|
|
||||||
var signature = privKey.sign(signatureHash)
|
|
||||||
|
|
||||||
// enforce signing in order of public keys
|
|
||||||
assert(input.pubKeys.some(function(pubKey, i) {
|
assert(input.pubKeys.some(function(pubKey, i) {
|
||||||
if (!privKey.pub.Q.equals(pubKey.Q)) return false
|
if (!privKey.pub.Q.equals(pubKey.Q)) return false
|
||||||
|
|
||||||
assert(!input.signatures[i], 'Signature already exists')
|
assert(!input.signatures[i], 'Signature already exists')
|
||||||
|
var signatureScript = input.redeemScript || input.prevOutScript
|
||||||
|
var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType)
|
||||||
|
var signature = privKey.sign(signatureHash)
|
||||||
input.signatures[i] = signature
|
input.signatures[i] = signature
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}), 'privateKey cannot sign for this input')
|
}, this), 'privateKey cannot sign for this input')
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TransactionBuilder
|
module.exports = TransactionBuilder
|
||||||
|
|
7
test/fixtures/transaction_builder.json
vendored
7
test/fixtures/transaction_builder.json
vendored
|
@ -206,7 +206,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Incomplete transaction w/ prevTxScript defined",
|
"description": "Incomplete transaction w/ prevTxScript defined",
|
||||||
"exception": "Transaction is not complete",
|
"exception": "Transaction is missing signatures",
|
||||||
"alwaysThrows": true,
|
"alwaysThrows": true,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
|
@ -240,7 +240,8 @@
|
||||||
],
|
],
|
||||||
"sign": [
|
"sign": [
|
||||||
{
|
{
|
||||||
"exception": "pubkeyhash doesn\\'t support multiple signatures",
|
"description": "Too many signatures - pubKeyHash",
|
||||||
|
"exception": "Signature already exists",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
"txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
@ -406,6 +407,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"description": "Too many signatures - scriptHash(multisig 1-of-1)",
|
||||||
"exception": "Signature already exists",
|
"exception": "Signature already exists",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
|
@ -418,7 +420,6 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
|
"privKey": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
|
||||||
"redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG",
|
|
||||||
"throws": true
|
"throws": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Reference in a new issue