mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[DEV-53] SigHashSingle now errors when the index is wrong
* [DEV-50] Remove the Multisig bug requiring a dummy push * [DEV-53] SigHashSingle now errors when the index is wrong * [DEV-53] Fixed tests for SIGHASH_SINGLE * [DEV-53] Removed redundant part of comment
This commit is contained in:
parent
4d099d51cb
commit
3f3a10c695
@ -218,5 +218,13 @@
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 CHECKSEQUENCEVERIFY 1"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
|
||||
|
||||
|
||||
["The following tests for the fix of a btc bug in the handling of SIGHASH_SINGLE"],
|
||||
["It results in signing the constant 1, instead of something generated based on the transaction,"],
|
||||
["when the input doing the signing has an index greater than the maximum output index"],
|
||||
["We have fixed this bug and it should no longer be part of the concensus rules"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"], ["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"]],
|
||||
"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
|
@ -36,12 +36,6 @@
|
||||
["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
|
||||
"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
|
||||
|
||||
["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
|
||||
["It results in signing the constant 1, instead of something generated based on the transaction,"],
|
||||
["when the input doing the signing has an index greater than the maximum output index"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"], ["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"]],
|
||||
"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["An invalid P2SH Transaction"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
|
||||
"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"],
|
||||
@ -160,19 +154,6 @@
|
||||
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
|
||||
|
||||
["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
|
||||
[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
|
||||
["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]],
|
||||
"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd2501483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"],
|
||||
|
||||
["Same idea, but with bare CHECKMULTISIG"],
|
||||
[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
|
||||
["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
|
||||
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce0100000092483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["CHECKLOCKTIMEVERIFY tests"],
|
||||
|
||||
["By-height locks, with argument == 0 and == tx nLockTime"],
|
||||
|
@ -175,6 +175,10 @@ const (
|
||||
// one of the supported types.
|
||||
ErrInvalidSigHashType
|
||||
|
||||
// ErrInvalidSigHashSingleIndex is returned what a signature of type
|
||||
// SigHashSingle points to a non-existing output
|
||||
ErrInvalidSigHashSingleIndex
|
||||
|
||||
// ErrSigDER is returned when a signature is not a canonically-encoded
|
||||
// DER signature.
|
||||
ErrSigDER
|
||||
@ -229,46 +233,47 @@ const (
|
||||
|
||||
// Map of ErrorCode values back to their constant names for pretty printing.
|
||||
var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrInternal: "ErrInternal",
|
||||
ErrInvalidFlags: "ErrInvalidFlags",
|
||||
ErrInvalidIndex: "ErrInvalidIndex",
|
||||
ErrUnsupportedAddress: "ErrUnsupportedAddress",
|
||||
ErrNotMultisigScript: "ErrNotMultisigScript",
|
||||
ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs",
|
||||
ErrTooMuchNullData: "ErrTooMuchNullData",
|
||||
ErrEarlyReturn: "ErrEarlyReturn",
|
||||
ErrEmptyStack: "ErrEmptyStack",
|
||||
ErrEvalFalse: "ErrEvalFalse",
|
||||
ErrScriptUnfinished: "ErrScriptUnfinished",
|
||||
ErrInvalidProgramCounter: "ErrInvalidProgramCounter",
|
||||
ErrScriptTooBig: "ErrScriptTooBig",
|
||||
ErrElementTooBig: "ErrElementTooBig",
|
||||
ErrTooManyOperations: "ErrTooManyOperations",
|
||||
ErrStackOverflow: "ErrStackOverflow",
|
||||
ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount",
|
||||
ErrInvalidSignatureCount: "ErrInvalidSignatureCount",
|
||||
ErrNumberTooBig: "ErrNumberTooBig",
|
||||
ErrVerify: "ErrVerify",
|
||||
ErrEqualVerify: "ErrEqualVerify",
|
||||
ErrNumEqualVerify: "ErrNumEqualVerify",
|
||||
ErrCheckSigVerify: "ErrCheckSigVerify",
|
||||
ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify",
|
||||
ErrDisabledOpcode: "ErrDisabledOpcode",
|
||||
ErrReservedOpcode: "ErrReservedOpcode",
|
||||
ErrMalformedPush: "ErrMalformedPush",
|
||||
ErrInvalidStackOperation: "ErrInvalidStackOperation",
|
||||
ErrUnbalancedConditional: "ErrUnbalancedConditional",
|
||||
ErrMinimalData: "ErrMinimalData",
|
||||
ErrInvalidSigHashType: "ErrInvalidSigHashType",
|
||||
ErrSigDER: "ErrSigDER",
|
||||
ErrSigHighS: "ErrSigHighS",
|
||||
ErrNotPushOnly: "ErrNotPushOnly",
|
||||
ErrPubKeyType: "ErrPubKeyType",
|
||||
ErrCleanStack: "ErrCleanStack",
|
||||
ErrNullFail: "ErrNullFail",
|
||||
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
||||
ErrNegativeLockTime: "ErrNegativeLockTime",
|
||||
ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime",
|
||||
ErrInternal: "ErrInternal",
|
||||
ErrInvalidFlags: "ErrInvalidFlags",
|
||||
ErrInvalidIndex: "ErrInvalidIndex",
|
||||
ErrUnsupportedAddress: "ErrUnsupportedAddress",
|
||||
ErrNotMultisigScript: "ErrNotMultisigScript",
|
||||
ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs",
|
||||
ErrTooMuchNullData: "ErrTooMuchNullData",
|
||||
ErrEarlyReturn: "ErrEarlyReturn",
|
||||
ErrEmptyStack: "ErrEmptyStack",
|
||||
ErrEvalFalse: "ErrEvalFalse",
|
||||
ErrScriptUnfinished: "ErrScriptUnfinished",
|
||||
ErrInvalidProgramCounter: "ErrInvalidProgramCounter",
|
||||
ErrScriptTooBig: "ErrScriptTooBig",
|
||||
ErrElementTooBig: "ErrElementTooBig",
|
||||
ErrTooManyOperations: "ErrTooManyOperations",
|
||||
ErrStackOverflow: "ErrStackOverflow",
|
||||
ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount",
|
||||
ErrInvalidSignatureCount: "ErrInvalidSignatureCount",
|
||||
ErrNumberTooBig: "ErrNumberTooBig",
|
||||
ErrVerify: "ErrVerify",
|
||||
ErrEqualVerify: "ErrEqualVerify",
|
||||
ErrNumEqualVerify: "ErrNumEqualVerify",
|
||||
ErrCheckSigVerify: "ErrCheckSigVerify",
|
||||
ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify",
|
||||
ErrDisabledOpcode: "ErrDisabledOpcode",
|
||||
ErrReservedOpcode: "ErrReservedOpcode",
|
||||
ErrMalformedPush: "ErrMalformedPush",
|
||||
ErrInvalidStackOperation: "ErrInvalidStackOperation",
|
||||
ErrUnbalancedConditional: "ErrUnbalancedConditional",
|
||||
ErrMinimalData: "ErrMinimalData",
|
||||
ErrInvalidSigHashType: "ErrInvalidSigHashType",
|
||||
ErrInvalidSigHashSingleIndex: "ErrInvalidSigHashSingleIndex",
|
||||
ErrSigDER: "ErrSigDER",
|
||||
ErrSigHighS: "ErrSigHighS",
|
||||
ErrNotPushOnly: "ErrNotPushOnly",
|
||||
ErrPubKeyType: "ErrPubKeyType",
|
||||
ErrCleanStack: "ErrCleanStack",
|
||||
ErrNullFail: "ErrNullFail",
|
||||
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
||||
ErrNegativeLockTime: "ErrNegativeLockTime",
|
||||
ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime",
|
||||
}
|
||||
|
||||
// String returns the ErrorCode as a human-readable name.
|
||||
|
@ -47,6 +47,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
||||
{ErrUnbalancedConditional, "ErrUnbalancedConditional"},
|
||||
{ErrMinimalData, "ErrMinimalData"},
|
||||
{ErrInvalidSigHashType, "ErrInvalidSigHashType"},
|
||||
{ErrInvalidSigHashSingleIndex, "ErrInvalidSigHashSingleIndex"},
|
||||
{ErrSigDER, "ErrSigDER"},
|
||||
{ErrSigHighS, "ErrSigHighS"},
|
||||
{ErrNotPushOnly, "ErrNotPushOnly"},
|
||||
|
@ -2053,7 +2053,11 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
|
||||
subScript = removeOpcodeByData(subScript, fullSigBytes)
|
||||
|
||||
// Generate the signature hash based on the signature hash type.
|
||||
hash := calcSignatureHash(subScript, hashType, &vm.tx, vm.txIdx)
|
||||
hash, err := calcSignatureHash(subScript, hashType, &vm.tx, vm.txIdx)
|
||||
if err != nil {
|
||||
vm.dstack.PushBool(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
pubKey, err := btcec.ParsePubKey(pkBytes, btcec.S256())
|
||||
if err != nil {
|
||||
@ -2279,7 +2283,10 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
|
||||
}
|
||||
|
||||
// Generate the signature hash based on the signature hash type.
|
||||
hash := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx)
|
||||
hash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var valid bool
|
||||
if vm.sigCache != nil {
|
||||
|
@ -735,8 +735,12 @@ func TestCalcSignatureHash(t *testing.T) {
|
||||
}
|
||||
|
||||
hashType := SigHashType(testVecF64ToUint32(test[3].(float64)))
|
||||
hash := calcSignatureHash(parsedScript, hashType, &tx,
|
||||
hash, err := calcSignatureHash(parsedScript, hashType, &tx,
|
||||
int(test[2].(float64)))
|
||||
if err != nil {
|
||||
t.Errorf("TestCalcSignatureHash failed test #%d: "+
|
||||
"Failed calculating signature hash: %s", i, err)
|
||||
}
|
||||
|
||||
expectedHash, _ := chainhash.NewHashFromStr(test[4].(string))
|
||||
if !bytes.Equal(hash, expectedHash[:]) {
|
||||
|
@ -314,37 +314,21 @@ func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse output script: %v", err)
|
||||
}
|
||||
return calcSignatureHash(parsedScript, hashType, tx, idx), nil
|
||||
return calcSignatureHash(parsedScript, hashType, tx, idx)
|
||||
}
|
||||
|
||||
// calcSignatureHash will, given a script and hash type for the current script
|
||||
// engine instance, calculate the signature hash to be used for signing and
|
||||
// verification.
|
||||
func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) []byte {
|
||||
func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) ([]byte, error) {
|
||||
// The SigHashSingle signature type signs only the corresponding input
|
||||
// and output (the output with the same index number as the input).
|
||||
//
|
||||
// Since transactions can have more inputs than outputs, this means it
|
||||
// is improper to use SigHashSingle on input indices that don't have a
|
||||
// corresponding output.
|
||||
//
|
||||
// A bug in the original Satoshi client implementation means specifying
|
||||
// an index that is out of range results in a signature hash of 1 (as a
|
||||
// uint256 little endian). The original intent appeared to be to
|
||||
// indicate failure, but unfortunately, it was never checked and thus is
|
||||
// treated as the actual signature hash. This buggy behavior is now
|
||||
// part of the consensus and a hard fork would be required to fix it.
|
||||
//
|
||||
// Due to this, care must be taken by software that creates transactions
|
||||
// which make use of SigHashSingle because it can lead to an extremely
|
||||
// dangerous situation where the invalid inputs will end up signing a
|
||||
// hash of 1. This in turn presents an opportunity for attackers to
|
||||
// cleverly construct transactions which can steal those coins provided
|
||||
// they can reuse signatures.
|
||||
if hashType&sigHashMask == SigHashSingle && idx >= len(tx.TxOut) {
|
||||
var hash chainhash.Hash
|
||||
hash[0] = 0x01
|
||||
return hash[:]
|
||||
return nil, scriptError(ErrInvalidSigHashSingleIndex, "sigHashSingle index out of bounds")
|
||||
}
|
||||
|
||||
// Remove all instances of OP_CODESEPARATOR from the script.
|
||||
@ -409,7 +393,7 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.Msg
|
||||
wbuf := bytes.NewBuffer(make([]byte, 0, txCopy.SerializeSize()+4))
|
||||
txCopy.Serialize(wbuf)
|
||||
binary.Write(wbuf, binary.LittleEndian, hashType)
|
||||
return chainhash.DoubleHashB(wbuf.Bytes())
|
||||
return chainhash.DoubleHashB(wbuf.Bytes()), nil
|
||||
}
|
||||
|
||||
// asSmallInt returns the passed opcode, which must be true according to
|
||||
|
@ -162,10 +162,10 @@ func sign(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
// and nrequired are the result of extracting the addresses from pkscript.
|
||||
// The return value is the best effort merging of the two scripts. Calling this
|
||||
// function with addresses, class and nrequired that do not match pkScript is
|
||||
// an error and results in undefined behaviour.
|
||||
// an error.
|
||||
func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
pkScript []byte, class ScriptClass, addresses []btcutil.Address,
|
||||
nRequired int, sigScript, prevScript []byte) []byte {
|
||||
nRequired int, sigScript, prevScript []byte) ([]byte, error) {
|
||||
|
||||
// TODO: the scripthash and multisig paths here are overly
|
||||
// inefficient in that they will recompute already known data.
|
||||
@ -177,11 +177,11 @@ func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
// this could be a lot less inefficient.
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil || len(sigPops) == 0 {
|
||||
return prevScript
|
||||
return prevScript, nil
|
||||
}
|
||||
prevPops, err := parseScript(prevScript)
|
||||
if err != nil || len(prevPops) == 0 {
|
||||
return sigScript
|
||||
return sigScript, nil
|
||||
}
|
||||
|
||||
// assume that script in sigPops is the correct one, we just
|
||||
@ -197,15 +197,17 @@ func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
prevScript, _ := unparseScript(prevPops)
|
||||
|
||||
// Merge
|
||||
mergedScript := mergeScripts(chainParams, tx, idx, script,
|
||||
mergedScript, err := mergeScripts(chainParams, tx, idx, script,
|
||||
class, addresses, nrequired, sigScript, prevScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Reappend the script and return the result.
|
||||
builder := NewScriptBuilder()
|
||||
builder.AddOps(mergedScript)
|
||||
builder.AddData(script)
|
||||
finalScript, _ := builder.Script()
|
||||
return finalScript
|
||||
return builder.Script()
|
||||
case MultiSigTy:
|
||||
return mergeMultiSig(tx, idx, addresses, nRequired, pkScript,
|
||||
sigScript, prevScript)
|
||||
@ -218,34 +220,32 @@ func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
// correct (this matches behaviour of the reference implementation).
|
||||
default:
|
||||
if len(sigScript) > len(prevScript) {
|
||||
return sigScript
|
||||
return sigScript, nil
|
||||
}
|
||||
return prevScript
|
||||
return prevScript, nil
|
||||
}
|
||||
}
|
||||
|
||||
// mergeMultiSig combines the two signature scripts sigScript and prevScript
|
||||
// that both provide signatures for pkScript in output idx of tx. addresses
|
||||
// and nRequired should be the results from extracting the addresses from
|
||||
// pkScript. Since this function is internal only we assume that the arguments
|
||||
// have come from other functions internally and thus are all consistent with
|
||||
// each other, behaviour is undefined if this contract is broken.
|
||||
// pkScript.
|
||||
func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []btcutil.Address,
|
||||
nRequired int, pkScript, sigScript, prevScript []byte) []byte {
|
||||
nRequired int, pkScript, sigScript, prevScript []byte) ([]byte, error) {
|
||||
|
||||
// This is an internal only function and we already parsed this script
|
||||
// as ok for multisig (this is how we got here), so if this fails then
|
||||
// all assumptions are broken and who knows which way is up?
|
||||
pkPops, _ := parseScript(pkScript)
|
||||
pkPops, err := parseScript(pkScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil || len(sigPops) == 0 {
|
||||
return prevScript
|
||||
return prevScript, nil
|
||||
}
|
||||
|
||||
prevPops, err := parseScript(prevScript)
|
||||
if err != nil || len(prevPops) == 0 {
|
||||
return sigScript
|
||||
return sigScript, nil
|
||||
}
|
||||
|
||||
// Convenience function to avoid duplication.
|
||||
@ -290,7 +290,10 @@ sigLoop:
|
||||
// however, assume no sigs etc are in the script since that
|
||||
// would make the transaction nonstandard and thus not
|
||||
// MultiSigTy, so we just need to hash the full thing.
|
||||
hash := calcSignatureHash(pkPops, hashType, tx, idx)
|
||||
hash, err := calcSignatureHash(pkPops, hashType, tx, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, addr := range addresses {
|
||||
// All multisig addresses should be pubkey addresses
|
||||
@ -336,7 +339,7 @@ sigLoop:
|
||||
}
|
||||
|
||||
script, _ := builder.Script()
|
||||
return script
|
||||
return script, nil
|
||||
}
|
||||
|
||||
// KeyDB is an interface type provided to SignTxOutput, it encapsulates
|
||||
@ -403,7 +406,6 @@ func SignTxOutput(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||
}
|
||||
|
||||
// Merge scripts. with any previous data, if any.
|
||||
mergedScript := mergeScripts(chainParams, tx, idx, pkScript, class,
|
||||
return mergeScripts(chainParams, tx, idx, pkScript, class,
|
||||
addresses, nrequired, sigScript, previousScript)
|
||||
return mergedScript, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user