You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1714 lines
43 KiB
1714 lines
43 KiB
// Copyright (c) 2013-2015 The btcsuite developers |
|
// Use of this source code is governed by an ISC |
|
// license that can be found in the LICENSE file. |
|
|
|
package txscript_test |
|
|
|
import ( |
|
"errors" |
|
"fmt" |
|
"testing" |
|
|
|
"github.com/btcsuite/btcd/btcec" |
|
"github.com/btcsuite/btcd/chaincfg" |
|
"github.com/btcsuite/btcd/txscript" |
|
"github.com/btcsuite/btcd/wire" |
|
"github.com/btcsuite/btcutil" |
|
) |
|
|
|
type addressToKey struct { |
|
key *btcec.PrivateKey |
|
compressed bool |
|
} |
|
|
|
func mkGetKey(keys map[string]addressToKey) txscript.KeyDB { |
|
if keys == nil { |
|
return txscript.KeyClosure(func(addr btcutil.Address) (*btcec.PrivateKey, |
|
bool, error) { |
|
return nil, false, errors.New("nope") |
|
}) |
|
} |
|
return txscript.KeyClosure(func(addr btcutil.Address) (*btcec.PrivateKey, |
|
bool, error) { |
|
a2k, ok := keys[addr.EncodeAddress()] |
|
if !ok { |
|
return nil, false, errors.New("nope") |
|
} |
|
return a2k.key, a2k.compressed, nil |
|
}) |
|
} |
|
|
|
func mkGetScript(scripts map[string][]byte) txscript.ScriptDB { |
|
if scripts == nil { |
|
return txscript.ScriptClosure(func(addr btcutil.Address) ( |
|
[]byte, error) { |
|
return nil, errors.New("nope") |
|
}) |
|
} |
|
return txscript.ScriptClosure(func(addr btcutil.Address) ([]byte, |
|
error) { |
|
script, ok := scripts[addr.EncodeAddress()] |
|
if !ok { |
|
return nil, errors.New("nope") |
|
} |
|
return script, nil |
|
}) |
|
} |
|
|
|
func checkScripts(msg string, tx *wire.MsgTx, idx int, sigScript, pkScript []byte) error { |
|
tx.TxIn[idx].SignatureScript = sigScript |
|
vm, err := txscript.NewEngine(pkScript, tx, idx, |
|
txscript.ScriptBip16|txscript.ScriptVerifyDERSignatures) |
|
if err != nil { |
|
return fmt.Errorf("failed to make script engine for %s: %v", |
|
msg, err) |
|
} |
|
|
|
err = vm.Execute() |
|
if err != nil { |
|
return fmt.Errorf("invalid script signature for %s: %v", msg, |
|
err) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func signAndCheck(msg string, tx *wire.MsgTx, idx int, pkScript []byte, |
|
hashType txscript.SigHashType, kdb txscript.KeyDB, sdb txscript.ScriptDB, |
|
previousScript []byte) error { |
|
|
|
sigScript, err := txscript.SignTxOutput(&chaincfg.TestNet3Params, tx, |
|
idx, pkScript, hashType, kdb, sdb, nil) |
|
if err != nil { |
|
return fmt.Errorf("failed to sign output %s: %v", msg, err) |
|
} |
|
|
|
return checkScripts(msg, tx, idx, sigScript, pkScript) |
|
} |
|
|
|
func TestSignTxOutput(t *testing.T) { |
|
t.Parallel() |
|
|
|
// make key |
|
// make script based on key. |
|
// sign with magic pixie dust. |
|
hashTypes := []txscript.SigHashType{ |
|
txscript.SigHashOld, // no longer used but should act like all |
|
txscript.SigHashAll, |
|
txscript.SigHashNone, |
|
txscript.SigHashSingle, |
|
txscript.SigHashAll | txscript.SigHashAnyOneCanPay, |
|
txscript.SigHashNone | txscript.SigHashAnyOneCanPay, |
|
txscript.SigHashSingle | txscript.SigHashAnyOneCanPay, |
|
} |
|
tx := &wire.MsgTx{ |
|
Version: 1, |
|
TxIn: []*wire.TxIn{ |
|
&wire.TxIn{ |
|
PreviousOutPoint: wire.OutPoint{ |
|
Hash: wire.ShaHash{}, |
|
Index: 0, |
|
}, |
|
Sequence: 4294967295, |
|
}, |
|
&wire.TxIn{ |
|
PreviousOutPoint: wire.OutPoint{ |
|
Hash: wire.ShaHash{}, |
|
Index: 1, |
|
}, |
|
Sequence: 4294967295, |
|
}, |
|
&wire.TxIn{ |
|
PreviousOutPoint: wire.OutPoint{ |
|
Hash: wire.ShaHash{}, |
|
Index: 2, |
|
}, |
|
Sequence: 4294967295, |
|
}, |
|
}, |
|
TxOut: []*wire.TxOut{ |
|
&wire.TxOut{ |
|
Value: 1, |
|
}, |
|
&wire.TxOut{ |
|
Value: 2, |
|
}, |
|
&wire.TxOut{ |
|
Value: 3, |
|
}, |
|
}, |
|
LockTime: 0, |
|
} |
|
|
|
// Pay to Pubkey Hash (uncompressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, pkScript, hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(nil), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to Pubkey Hash (uncompressed) (merging with correct) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(nil), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(nil), sigScript) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, pkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to Pubkey Hash (compressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, pkScript, hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(nil), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to Pubkey Hash (compressed) with duplicate merge |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(nil), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(nil), sigScript) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, pkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (uncompressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, pkScript, hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(nil), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (uncompressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(nil), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(nil), sigScript) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, pkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (compressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, pkScript, hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(nil), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (compressed) with duplicate merge |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(nil), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, pkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(nil), sigScript) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, pkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// As before, but with p2sh now. |
|
// Pay to Pubkey Hash (uncompressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
break |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, scriptPkScript, |
|
hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to Pubkey Hash (uncompressed) with duplicate merge |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
break |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, scriptPkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to Pubkey Hash (compressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, scriptPkScript, |
|
hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to Pubkey Hash (compressed) with duplicate merge |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKeyHash( |
|
btcutil.Hash160(pk), &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, scriptPkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (uncompressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, scriptPkScript, |
|
hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (uncompressed) with duplicate merge |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeUncompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, false}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, scriptPkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (compressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, scriptPkScript, |
|
hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Pay to PubKey (compressed) |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk := (*btcec.PublicKey)(&key.PublicKey). |
|
SerializeCompressed() |
|
address, err := btcutil.NewAddressPubKey(pk, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.PayToAddrScript(address) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// by the above loop, this should be valid, now sign |
|
// again and merge. |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address.EncodeAddress(): {key, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s a "+ |
|
"second time: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, scriptPkScript) |
|
if err != nil { |
|
t.Errorf("twice signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Basic Multisig |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key1, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk1 := (*btcec.PublicKey)(&key1.PublicKey). |
|
SerializeCompressed() |
|
address1, err := btcutil.NewAddressPubKey(pk1, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
key2, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey 2 for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk2 := (*btcec.PublicKey)(&key2.PublicKey). |
|
SerializeCompressed() |
|
address2, err := btcutil.NewAddressPubKey(pk2, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address 2 for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.MultiSigScript( |
|
[]*btcutil.AddressPubKey{address1, address2}, |
|
2) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
if err := signAndCheck(msg, tx, i, scriptPkScript, |
|
hashType, |
|
mkGetKey(map[string]addressToKey{ |
|
address1.EncodeAddress(): {key1, true}, |
|
address2.EncodeAddress(): {key2, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil); err != nil { |
|
t.Error(err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Two part multisig, sign with one key then the other. |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key1, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk1 := (*btcec.PublicKey)(&key1.PublicKey). |
|
SerializeCompressed() |
|
address1, err := btcutil.NewAddressPubKey(pk1, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
key2, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey 2 for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk2 := (*btcec.PublicKey)(&key2.PublicKey). |
|
SerializeCompressed() |
|
address2, err := btcutil.NewAddressPubKey(pk2, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address 2 for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.MultiSigScript( |
|
[]*btcutil.AddressPubKey{address1, address2}, |
|
2) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address1.EncodeAddress(): {key1, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// Only 1 out of 2 signed, this *should* fail. |
|
if checkScripts(msg, tx, i, sigScript, |
|
scriptPkScript) == nil { |
|
t.Errorf("part signed script valid for %s", msg) |
|
break |
|
} |
|
|
|
// Sign with the other key and merge |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address2.EncodeAddress(): {key2, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), sigScript) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, err) |
|
break |
|
} |
|
|
|
err = checkScripts(msg, tx, i, sigScript, |
|
scriptPkScript) |
|
if err != nil { |
|
t.Errorf("fully signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
|
|
// Two part multisig, sign with one key then both, check key dedup |
|
// correctly. |
|
for _, hashType := range hashTypes { |
|
for i := range tx.TxIn { |
|
msg := fmt.Sprintf("%d:%d", hashType, i) |
|
|
|
key1, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk1 := (*btcec.PublicKey)(&key1.PublicKey). |
|
SerializeCompressed() |
|
address1, err := btcutil.NewAddressPubKey(pk1, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
key2, err := btcec.NewPrivateKey(btcec.S256()) |
|
if err != nil { |
|
t.Errorf("failed to make privKey 2 for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pk2 := (*btcec.PublicKey)(&key2.PublicKey). |
|
SerializeCompressed() |
|
address2, err := btcutil.NewAddressPubKey(pk2, |
|
&chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make address 2 for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
pkScript, err := txscript.MultiSigScript( |
|
[]*btcutil.AddressPubKey{address1, address2}, |
|
2) |
|
if err != nil { |
|
t.Errorf("failed to make pkscript "+ |
|
"for %s: %v", msg, err) |
|
} |
|
|
|
scriptAddr, err := btcutil.NewAddressScriptHash( |
|
pkScript, &chaincfg.TestNet3Params) |
|
if err != nil { |
|
t.Errorf("failed to make p2sh addr for %s: %v", |
|
msg, err) |
|
break |
|
} |
|
|
|
scriptPkScript, err := txscript.PayToAddrScript( |
|
scriptAddr) |
|
if err != nil { |
|
t.Errorf("failed to make script pkscript for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
|
|
sigScript, err := txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address1.EncodeAddress(): {key1, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), nil) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, |
|
err) |
|
break |
|
} |
|
|
|
// Only 1 out of 2 signed, this *should* fail. |
|
if checkScripts(msg, tx, i, sigScript, |
|
scriptPkScript) == nil { |
|
t.Errorf("part signed script valid for %s", msg) |
|
break |
|
} |
|
|
|
// Sign with the other key and merge |
|
sigScript, err = txscript.SignTxOutput( |
|
&chaincfg.TestNet3Params, tx, i, scriptPkScript, |
|
hashType, mkGetKey(map[string]addressToKey{ |
|
address1.EncodeAddress(): {key1, true}, |
|
address2.EncodeAddress(): {key2, true}, |
|
}), mkGetScript(map[string][]byte{ |
|
scriptAddr.EncodeAddress(): pkScript, |
|
}), sigScript) |
|
if err != nil { |
|
t.Errorf("failed to sign output %s: %v", msg, err) |
|
break |
|
} |
|
|
|
// Now we should pass. |
|
err = checkScripts(msg, tx, i, sigScript, |
|
scriptPkScript) |
|
if err != nil { |
|
t.Errorf("fully signed script invalid for "+ |
|
"%s: %v", msg, err) |
|
break |
|
} |
|
} |
|
} |
|
} |
|
|
|
type tstInput struct { |
|
txout *wire.TxOut |
|
sigscriptGenerates bool |
|
inputValidates bool |
|
indexOutOfRange bool |
|
} |
|
|
|
type tstSigScript struct { |
|
name string |
|
inputs []tstInput |
|
hashType txscript.SigHashType |
|
compress bool |
|
scriptAtWrongIndex bool |
|
} |
|
|
|
var coinbaseOutPoint = &wire.OutPoint{ |
|
Index: (1 << 32) - 1, |
|
} |
|
|
|
// Pregenerated private key, with associated public key and pkScripts |
|
// for the uncompressed and compressed hash160. |
|
var ( |
|
privKeyD = []byte{0x6b, 0x0f, 0xd8, 0xda, 0x54, 0x22, 0xd0, 0xb7, |
|
0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65, |
|
0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, |
|
0xd6, 0x0e, 0x06, 0x92} |
|
pubkeyX = []byte{0xb2, 0x52, 0xf0, 0x49, 0x85, 0x78, 0x03, 0x03, 0xc8, |
|
0x7d, 0xce, 0x51, 0x7f, 0xa8, 0x69, 0x0b, 0x91, 0x95, 0xf4, |
|
0xf3, 0x5c, 0x26, 0x73, 0x05, 0x05, 0xa2, 0xee, 0xbc, 0x09, |
|
0x38, 0x34, 0x3a} |
|
pubkeyY = []byte{0xb7, 0xc6, 0x7d, 0xb2, 0xe1, 0xff, 0xc8, 0x43, 0x1f, |
|
0x63, 0x32, 0x62, 0xaa, 0x60, 0xc6, 0x83, 0x30, 0xbd, 0x24, |
|
0x7e, 0xef, 0xdb, 0x6f, 0x2e, 0x8d, 0x56, 0xf0, 0x3c, 0x9f, |
|
0x6d, 0xb6, 0xf8} |
|
uncompressedPkScript = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, |
|
0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, |
|
0x53, 0x90, 0x0e, 0x0a, 0x86, 0xc9, 0xfa, 0x88, 0xac} |
|
compressedPkScript = []byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, |
|
0x61, 0x7e, 0x7c, 0x7a, 0x1c, 0x1f, 0xb2, 0x75, 0x79, 0x10, |
|
0x43, 0x65, 0x68, 0x27, 0x9d, 0x86, 0x88, 0xac} |
|
shortPkScript = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, |
|
0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, |
|
0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac} |
|
uncompressedAddrStr = "1L6fd93zGmtzkK6CsZFVVoCwzZV3MUtJ4F" |
|
compressedAddrStr = "14apLppt9zTq6cNw8SDfiJhk9PhkZrQtYZ" |
|
) |
|
|
|
// Pretend output amounts. |
|
const coinbaseVal = 2500000000 |
|
const fee = 5000000 |
|
|
|
var sigScriptTests = []tstSigScript{ |
|
{ |
|
name: "one input uncompressed", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "two inputs uncompressed", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal+fee, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "one input compressed", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, compressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: true, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "two inputs compressed", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, compressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal+fee, compressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: true, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "hashType SigHashNone", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashNone, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "hashType SigHashSingle", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashSingle, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "hashType SigHashAnyoneCanPay", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAnyOneCanPay, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "hashType non-standard", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: 0x04, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "invalid compression", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: false, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: true, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "short PkScript", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, shortPkScript), |
|
sigscriptGenerates: false, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: false, |
|
scriptAtWrongIndex: false, |
|
}, |
|
{ |
|
name: "valid script at wrong index", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal+fee, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: false, |
|
scriptAtWrongIndex: true, |
|
}, |
|
{ |
|
name: "index out of range", |
|
inputs: []tstInput{ |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
{ |
|
txout: wire.NewTxOut(coinbaseVal+fee, uncompressedPkScript), |
|
sigscriptGenerates: true, |
|
inputValidates: true, |
|
indexOutOfRange: false, |
|
}, |
|
}, |
|
hashType: txscript.SigHashAll, |
|
compress: false, |
|
scriptAtWrongIndex: true, |
|
}, |
|
} |
|
|
|
// Test the sigscript generation for valid and invalid inputs, all |
|
// hashTypes, and with and without compression. This test creates |
|
// sigscripts to spend fake coinbase inputs, as sigscripts cannot be |
|
// created for the MsgTxs in txTests, since they come from the blockchain |
|
// and we don't have the private keys. |
|
func TestSignatureScript(t *testing.T) { |
|
t.Parallel() |
|
|
|
privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyD) |
|
|
|
nexttest: |
|
for i := range sigScriptTests { |
|
tx := wire.NewMsgTx() |
|
|
|
output := wire.NewTxOut(500, []byte{txscript.OP_RETURN}) |
|
tx.AddTxOut(output) |
|
|
|
for _ = range sigScriptTests[i].inputs { |
|
txin := wire.NewTxIn(coinbaseOutPoint, nil) |
|
tx.AddTxIn(txin) |
|
} |
|
|
|
var script []byte |
|
var err error |
|
for j := range tx.TxIn { |
|
var idx int |
|
if sigScriptTests[i].inputs[j].indexOutOfRange { |
|
t.Errorf("at test %v", sigScriptTests[i].name) |
|
idx = len(sigScriptTests[i].inputs) |
|
} else { |
|
idx = j |
|
} |
|
script, err = txscript.SignatureScript(tx, idx, |
|
sigScriptTests[i].inputs[j].txout.PkScript, |
|
sigScriptTests[i].hashType, privKey, |
|
sigScriptTests[i].compress) |
|
|
|
if (err == nil) != sigScriptTests[i].inputs[j].sigscriptGenerates { |
|
if err == nil { |
|
t.Errorf("passed test '%v' incorrectly", |
|
sigScriptTests[i].name) |
|
} else { |
|
t.Errorf("failed test '%v': %v", |
|
sigScriptTests[i].name, err) |
|
} |
|
continue nexttest |
|
} |
|
if !sigScriptTests[i].inputs[j].sigscriptGenerates { |
|
// done with this test |
|
continue nexttest |
|
} |
|
|
|
tx.TxIn[j].SignatureScript = script |
|
} |
|
|
|
// If testing using a correct sigscript but for an incorrect |
|
// index, use last input script for first input. Requires > 0 |
|
// inputs for test. |
|
if sigScriptTests[i].scriptAtWrongIndex { |
|
tx.TxIn[0].SignatureScript = script |
|
sigScriptTests[i].inputs[0].inputValidates = false |
|
} |
|
|
|
// Validate tx input scripts |
|
scriptFlags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures |
|
for j := range tx.TxIn { |
|
vm, err := txscript.NewEngine(sigScriptTests[i]. |
|
inputs[j].txout.PkScript, tx, j, scriptFlags) |
|
if err != nil { |
|
t.Errorf("cannot create script vm for test %v: %v", |
|
sigScriptTests[i].name, err) |
|
continue nexttest |
|
} |
|
err = vm.Execute() |
|
if (err == nil) != sigScriptTests[i].inputs[j].inputValidates { |
|
if err == nil { |
|
t.Errorf("passed test '%v' validation incorrectly: %v", |
|
sigScriptTests[i].name, err) |
|
} else { |
|
t.Errorf("failed test '%v' validation: %v", |
|
sigScriptTests[i].name, err) |
|
} |
|
continue nexttest |
|
} |
|
} |
|
} |
|
}
|
|
|