WIP: next hard fork #5
1 changed files with 51 additions and 37 deletions
|
@ -218,37 +218,44 @@ func sign(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||||
// pkScript. Since this function is internal only we assume that the arguments
|
// pkScript. Since this function is internal only we assume that the arguments
|
||||||
// have come from other functions internally and thus are all consistent with
|
// have come from other functions internally and thus are all consistent with
|
||||||
// each other, behaviour is undefined if this contract is broken.
|
// each other, behaviour is undefined if this contract is broken.
|
||||||
|
//
|
||||||
|
// NOTE: This function is only valid for version 0 scripts. Since the function
|
||||||
|
// does not accept a script version, the results are undefined for other script
|
||||||
|
// versions.
|
||||||
func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []btcutil.Address,
|
func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []btcutil.Address,
|
||||||
nRequired int, pkScript, sigScript, prevScript []byte) []byte {
|
nRequired int, pkScript, sigScript, prevScript []byte) []byte {
|
||||||
|
|
||||||
// This is an internal only function and we already parsed this script
|
// Nothing to merge if either the new or previous signature scripts are
|
||||||
// as ok for multisig (this is how we got here), so if this fails then
|
// empty.
|
||||||
// all assumptions are broken and who knows which way is up?
|
if len(sigScript) == 0 {
|
||||||
pkPops, _ := parseScript(pkScript)
|
|
||||||
|
|
||||||
sigPops, err := parseScript(sigScript)
|
|
||||||
if err != nil || len(sigPops) == 0 {
|
|
||||||
return prevScript
|
return prevScript
|
||||||
}
|
}
|
||||||
|
if len(prevScript) == 0 {
|
||||||
prevPops, err := parseScript(prevScript)
|
|
||||||
if err != nil || len(prevPops) == 0 {
|
|
||||||
return sigScript
|
return sigScript
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience function to avoid duplication.
|
// Convenience function to avoid duplication.
|
||||||
extractSigs := func(pops []parsedOpcode, sigs [][]byte) [][]byte {
|
var possibleSigs [][]byte
|
||||||
for _, pop := range pops {
|
extractSigs := func(script []byte) error {
|
||||||
if len(pop.data) != 0 {
|
const scriptVersion = 0
|
||||||
sigs = append(sigs, pop.data)
|
tokenizer := MakeScriptTokenizer(scriptVersion, script)
|
||||||
|
for tokenizer.Next() {
|
||||||
|
if data := tokenizer.Data(); len(data) != 0 {
|
||||||
|
possibleSigs = append(possibleSigs, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sigs
|
return tokenizer.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
possibleSigs := make([][]byte, 0, len(sigPops)+len(prevPops))
|
// Attempt to extract signatures from the two scripts. Return the other
|
||||||
possibleSigs = extractSigs(sigPops, possibleSigs)
|
// script that is intended to be merged in the case signature extraction
|
||||||
possibleSigs = extractSigs(prevPops, possibleSigs)
|
// fails for some reason.
|
||||||
|
if err := extractSigs(sigScript); err != nil {
|
||||||
|
return prevScript
|
||||||
|
}
|
||||||
|
if err := extractSigs(prevScript); err != nil {
|
||||||
|
return sigScript
|
||||||
|
}
|
||||||
|
|
||||||
// Now we need to match the signatures to pubkeys, the only real way to
|
// Now we need to match the signatures to pubkeys, the only real way to
|
||||||
// do that is to try to verify them all and match it to the pubkey
|
// do that is to try to verify them all and match it to the pubkey
|
||||||
|
@ -278,10 +285,7 @@ sigLoop:
|
||||||
// however, assume no sigs etc are in the script since that
|
// however, assume no sigs etc are in the script since that
|
||||||
// would make the transaction nonstandard and thus not
|
// would make the transaction nonstandard and thus not
|
||||||
// MultiSigTy, so we just need to hash the full thing.
|
// MultiSigTy, so we just need to hash the full thing.
|
||||||
hash, err := calcSignatureHash(pkPops, hashType, tx, idx)
|
hash := calcSignatureHashRaw(pkScript, hashType, tx, idx)
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("cannot compute sighash: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range addresses {
|
for _, addr := range addresses {
|
||||||
// All multisig addresses should be pubkey addresses
|
// All multisig addresses should be pubkey addresses
|
||||||
|
@ -336,6 +340,10 @@ sigLoop:
|
||||||
// The return value is the best effort merging of the two scripts. Calling this
|
// 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
|
// function with addresses, class and nrequired that do not match pkScript is
|
||||||
// an error and results in undefined behaviour.
|
// an error and results in undefined behaviour.
|
||||||
|
//
|
||||||
|
// NOTE: This function is only valid for version 0 scripts. Since the function
|
||||||
|
// does not accept a script version, the results are undefined for other script
|
||||||
|
// versions.
|
||||||
func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||||
pkScript []byte, class ScriptClass, addresses []btcutil.Address,
|
pkScript []byte, class ScriptClass, addresses []btcutil.Address,
|
||||||
nRequired int, sigScript, prevScript []byte) []byte {
|
nRequired int, sigScript, prevScript []byte) []byte {
|
||||||
|
@ -344,32 +352,34 @@ func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||||
// inefficient in that they will recompute already known data.
|
// inefficient in that they will recompute already known data.
|
||||||
// some internal refactoring could probably make this avoid needless
|
// some internal refactoring could probably make this avoid needless
|
||||||
// extra calculations.
|
// extra calculations.
|
||||||
|
const scriptVersion = 0
|
||||||
switch class {
|
switch class {
|
||||||
case ScriptHashTy:
|
case ScriptHashTy:
|
||||||
// Remove the last push in the script and then recurse.
|
// Nothing to merge if either the new or previous signature
|
||||||
// this could be a lot less inefficient.
|
// scripts are empty or fail to parse.
|
||||||
sigPops, err := parseScript(sigScript)
|
if len(sigScript) == 0 ||
|
||||||
if err != nil || len(sigPops) == 0 {
|
checkScriptParses(scriptVersion, sigScript) != nil {
|
||||||
|
|
||||||
return prevScript
|
return prevScript
|
||||||
}
|
}
|
||||||
prevPops, err := parseScript(prevScript)
|
if len(prevScript) == 0 ||
|
||||||
if err != nil || len(prevPops) == 0 {
|
checkScriptParses(scriptVersion, prevScript) != nil {
|
||||||
|
|
||||||
return sigScript
|
return sigScript
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume that script in sigPops is the correct one, we just
|
// Remove the last push in the script and then recurse.
|
||||||
// made it.
|
// this could be a lot less inefficient.
|
||||||
script := sigPops[len(sigPops)-1].data
|
//
|
||||||
|
// Assume that final script is the correct one since it was just
|
||||||
|
// made and it is a pay-to-script-hash.
|
||||||
|
script := finalOpcodeData(scriptVersion, sigScript)
|
||||||
|
|
||||||
// We already know this information somewhere up the stack,
|
// We already know this information somewhere up the stack,
|
||||||
// therefore the error is ignored.
|
// therefore the error is ignored.
|
||||||
class, addresses, nrequired, _ :=
|
class, addresses, nrequired, _ :=
|
||||||
ExtractPkScriptAddrs(script, chainParams)
|
ExtractPkScriptAddrs(script, chainParams)
|
||||||
|
|
||||||
// regenerate scripts.
|
|
||||||
sigScript, _ := unparseScript(sigPops)
|
|
||||||
prevScript, _ := unparseScript(prevPops)
|
|
||||||
|
|
||||||
// Merge
|
// Merge
|
||||||
mergedScript := mergeScripts(chainParams, tx, idx, script,
|
mergedScript := mergeScripts(chainParams, tx, idx, script,
|
||||||
class, addresses, nrequired, sigScript, prevScript)
|
class, addresses, nrequired, sigScript, prevScript)
|
||||||
|
@ -380,6 +390,7 @@ func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||||
builder.AddData(script)
|
builder.AddData(script)
|
||||||
finalScript, _ := builder.Script()
|
finalScript, _ := builder.Script()
|
||||||
return finalScript
|
return finalScript
|
||||||
|
|
||||||
case MultiSigTy:
|
case MultiSigTy:
|
||||||
return mergeMultiSig(tx, idx, addresses, nRequired, pkScript,
|
return mergeMultiSig(tx, idx, addresses, nRequired, pkScript,
|
||||||
sigScript, prevScript)
|
sigScript, prevScript)
|
||||||
|
@ -408,8 +419,7 @@ type KeyDB interface {
|
||||||
type KeyClosure func(btcutil.Address) (*btcec.PrivateKey, bool, error)
|
type KeyClosure func(btcutil.Address) (*btcec.PrivateKey, bool, error)
|
||||||
|
|
||||||
// GetKey implements KeyDB by returning the result of calling the closure.
|
// GetKey implements KeyDB by returning the result of calling the closure.
|
||||||
func (kc KeyClosure) GetKey(address btcutil.Address) (*btcec.PrivateKey,
|
func (kc KeyClosure) GetKey(address btcutil.Address) (*btcec.PrivateKey, bool, error) {
|
||||||
bool, error) {
|
|
||||||
return kc(address)
|
return kc(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,6 +444,10 @@ func (sc ScriptClosure) GetScript(address btcutil.Address) ([]byte, error) {
|
||||||
// getScript. If previousScript is provided then the results in previousScript
|
// getScript. If previousScript is provided then the results in previousScript
|
||||||
// will be merged in a type-dependent manner with the newly generated.
|
// will be merged in a type-dependent manner with the newly generated.
|
||||||
// signature script.
|
// signature script.
|
||||||
|
//
|
||||||
|
// NOTE: This function is only valid for version 0 scripts. Since the function
|
||||||
|
// does not accept a script version, the results are undefined for other script
|
||||||
|
// versions.
|
||||||
func SignTxOutput(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
func SignTxOutput(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int,
|
||||||
pkScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB,
|
pkScript []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB,
|
||||||
previousScript []byte) ([]byte, error) {
|
previousScript []byte) ([]byte, error) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue