Browse Source

TxBuilder: remove initialized field from signature inputs

hk-custom-address
Daniel Cousens 10 years ago
parent
commit
3a371fccec
  1. 116
      src/transaction_builder.js
  2. 7
      test/fixtures/transaction_builder.json

116
src/transaction_builder.js

@ -33,60 +33,51 @@ 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': {
signatures = scriptSig.chunks.slice(1).map(function(chunk) {
if (chunk === ops.OP_0) return chunk
var parsed = ECSignature.parseScriptSignature(chunk)
hashType = parsed.hashType
return parsed.signature
})
if (redeemScript) {
pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
}
break
case 'pubkey':
parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0]) parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
hashType = parsed.hashType hashType = parsed.hashType
signatures = [parsed.signature] signatures = [parsed.signature]
initialized = true
if (redeemScript) { if (redeemScript) {
pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])] pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
} }
break break
}
case 'multisig': {
signatures = scriptSig.chunks.slice(1).map(function(chunk) {
if (chunk === ops.OP_0) return chunk
var parsed = ECSignature.parseScriptSignature(chunk)
hashType = parsed.hashType
return parsed.signature
})
default:
if (redeemScript) { if (redeemScript) {
initialized = true pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
} }
break 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

@ -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…
Cancel
Save