// DepositScript constructs and returns a multi-signature redemption script where // a certain number (Series.reqSigs) of the public keys belonging to the series // with the given ID are required to sign the transaction for it to be successful. func (p *Pool) DepositScript(seriesID uint32, branch Branch, index Index) ([]byte, error) { series := p.Series(seriesID) if series == nil { str := fmt.Sprintf("series #%d does not exist", seriesID) return nil, newError(ErrSeriesNotExists, str, nil) } pubKeys, err := branchOrder(series.publicKeys, branch) if err != nil { return nil, err } pks := make([]*btcutil.AddressPubKey, len(pubKeys)) for i, key := range pubKeys { child, err := key.Child(uint32(index)) // TODO: implement getting the next index until we find a valid one, // in case there is a hdkeychain.ErrInvalidChild. if err != nil { str := fmt.Sprintf("child #%d for this pubkey %d does not exist", index, i) return nil, newError(ErrKeyChain, str, err) } pubkey, err := child.ECPubKey() if err != nil { str := fmt.Sprintf("child #%d for this pubkey %d does not exist", index, i) return nil, newError(ErrKeyChain, str, err) } pks[i], err = btcutil.NewAddressPubKey(pubkey.SerializeCompressed(), p.manager.ChainParams()) if err != nil { str := fmt.Sprintf( "child #%d for this pubkey %d could not be converted to an address", index, i) return nil, newError(ErrKeyChain, str, err) } } script, err := txscript.MultiSigScript(pks, int(series.reqSigs)) if err != nil { str := fmt.Sprintf("error while making multisig script hash, %d", len(pks)) return nil, newError(ErrScriptCreation, str, err) } return script, nil }
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{ { PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 0, }, Sequence: 4294967295, }, { PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 1, }, Sequence: 4294967295, }, { PreviousOutPoint: wire.OutPoint{ Hash: wire.ShaHash{}, Index: 2, }, Sequence: 4294967295, }, }, TxOut: []*wire.TxOut{ { Value: 1, }, { Value: 2, }, { 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 } } } }
// TestMultiSigScript ensures the MultiSigScript function returns the expected // scripts and errors. func TestMultiSigScript(t *testing.T) { t.Parallel() // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg p2pkCompressedMain, err := btcutil.NewAddressPubKey(decodeHex("02192d7"+ "4d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed): %v", err) return } p2pkCompressed2Main, err := btcutil.NewAddressPubKey(decodeHex("03b0bd"+ "634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed 2): %v", err) return } p2pkUncompressedMain, err := btcutil.NewAddressPubKey(decodeHex("0411d"+ "b93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"+ "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b41"+ "2a3"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (uncompressed): %v", err) return } tests := []struct { keys []*btcutil.AddressPubKey nrequired int expected string err error }{ { []*btcutil.AddressPubKey{ p2pkCompressedMain, p2pkCompressed2Main, }, 1, "1 DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c" + "3ebec3a957724895dca52c6b4 DATA_33 0x03b0bd634" + "234abbb1ba1e986e884185c61cf43e001f9137f23c2c4" + "09273eb16e65 2 CHECKMULTISIG", nil, }, { []*btcutil.AddressPubKey{ p2pkCompressedMain, p2pkCompressed2Main, }, 2, "2 DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c" + "3ebec3a957724895dca52c6b4 DATA_33 0x03b0bd634" + "234abbb1ba1e986e884185c61cf43e001f9137f23c2c4" + "09273eb16e65 2 CHECKMULTISIG", nil, }, { []*btcutil.AddressPubKey{ p2pkCompressedMain, p2pkCompressed2Main, }, 3, "", txscript.ErrBadNumRequired, }, { []*btcutil.AddressPubKey{ p2pkUncompressedMain, }, 1, "1 DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382" + "e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf97444" + "64f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 " + "1 CHECKMULTISIG", nil, }, { []*btcutil.AddressPubKey{ p2pkUncompressedMain, }, 2, "", txscript.ErrBadNumRequired, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { script, err := txscript.MultiSigScript(test.keys, test.nrequired) if err != test.err { t.Errorf("MultiSigScript #%d unexpected error - "+ "got %v, want %v", i, err, test.err) continue } expected := mustParseShortForm(test.expected) if !bytes.Equal(script, expected) { t.Errorf("MultiSigScript #%d got: %x\nwant: %x", i, script, expected) continue } } }
func TestOpenChannelEncodeDecode(t *testing.T) { teardown, manager := createTestManager(t) defer teardown() privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), key[:]) addr, err := btcutil.NewAddressPubKey(pubKey.SerializeCompressed(), ActiveNetParams) if err != nil { t.Fatalf("unable to create delivery address") } script, err := txscript.MultiSigScript([]*btcutil.AddressPubKey{addr, addr}, 2) if err != nil { t.Fatalf("unable to create redeemScript") } state := OpenChannel{ TheirLNID: id, ChanID: id, MinFeePerKb: btcutil.Amount(5000), OurCommitKey: privKey, TheirCommitKey: pubKey, Capacity: btcutil.Amount(10000), OurBalance: btcutil.Amount(3000), TheirBalance: btcutil.Amount(7000), TheirCommitTx: testTx, OurCommitTx: testTx, FundingTx: testTx, MultiSigKey: privKey, FundingRedeemScript: script, TheirCurrentRevocation: rev, OurDeliveryAddress: addr, TheirDeliveryAddress: addr, CsvDelay: 5, NumUpdates: 1, TotalSatoshisSent: 1, TotalSatoshisReceived: 2, CreationTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), } var b bytes.Buffer if err := state.Encode(&b, manager); err != nil { t.Fatalf("unable to encode channel state: %v", err) } reader := bytes.NewReader(b.Bytes()) newState := &OpenChannel{} if err := newState.Decode(reader, manager); err != nil { t.Fatalf("unable to decode channel state: %v", err) } // The decoded channel state should be identical to what we stored // above. if !bytes.Equal(state.TheirLNID[:], newState.TheirLNID[:]) { t.Fatalf("their id doesn't match") } if !bytes.Equal(state.ChanID[:], newState.ChanID[:]) { t.Fatalf("chan id's don't match") } if state.MinFeePerKb != newState.MinFeePerKb { t.Fatalf("fee/kb doens't match") } if !bytes.Equal(state.OurCommitKey.Serialize(), newState.OurCommitKey.Serialize()) { t.Fatalf("our commit key dont't match") } if !bytes.Equal(state.TheirCommitKey.SerializeCompressed(), newState.TheirCommitKey.SerializeCompressed()) { t.Fatalf("their commit key dont't match") } if state.Capacity != newState.Capacity { t.Fatalf("capacity doesn't match") } if state.OurBalance != newState.OurBalance { t.Fatalf("our balance doesn't match") } if state.TheirBalance != newState.TheirBalance { t.Fatalf("their balance doesn't match") } var b1, b2 bytes.Buffer if err := state.TheirCommitTx.Serialize(&b1); err != nil { t.Fatalf("unable to serialize transaction") } if err := newState.TheirCommitTx.Serialize(&b2); err != nil { t.Fatalf("unable to serialize transaction") } if !bytes.Equal(b1.Bytes(), b2.Bytes()) { t.Fatalf("theirCommitTx doesn't match") } b1.Reset() b2.Reset() if err := state.OurCommitTx.Serialize(&b1); err != nil { t.Fatalf("unable to serialize transaction") } if err := newState.OurCommitTx.Serialize(&b2); err != nil { t.Fatalf("unable to serialize transaction") } if !bytes.Equal(b1.Bytes(), b2.Bytes()) { t.Fatalf("ourCommitTx doesn't match") } b1.Reset() b2.Reset() if err := state.FundingTx.Serialize(&b1); err != nil { t.Fatalf("unable to serialize transaction") } if err := newState.FundingTx.Serialize(&b2); err != nil { t.Fatalf("unable to serialize transaction") } if !bytes.Equal(b1.Bytes(), b2.Bytes()) { t.Fatalf("funding tx doesn't match") } if !bytes.Equal(state.MultiSigKey.Serialize(), newState.MultiSigKey.Serialize()) { t.Fatalf("multisig key doesn't match") } if !bytes.Equal(state.FundingRedeemScript, newState.FundingRedeemScript) { t.Fatalf("redeem script doesn't match") } if state.OurDeliveryAddress.EncodeAddress() != newState.OurDeliveryAddress.EncodeAddress() { t.Fatalf("our delivery address doesn't match") } if state.TheirDeliveryAddress.EncodeAddress() != newState.TheirDeliveryAddress.EncodeAddress() { t.Fatalf("their delivery address doesn't match") } if state.NumUpdates != newState.NumUpdates { t.Fatalf("num updates doesn't match: %v vs %v", state.NumUpdates, newState.NumUpdates) } if state.CsvDelay != newState.CsvDelay { t.Fatalf("csv delay doesn't match: %v vs %v", state.CsvDelay, newState.CsvDelay) } if state.TotalSatoshisSent != newState.TotalSatoshisSent { t.Fatalf("satoshis sent doesn't match: %v vs %v", state.TotalSatoshisSent, newState.TotalSatoshisSent) } if state.TotalSatoshisReceived != newState.TotalSatoshisReceived { t.Fatalf("satoshis received doesn't match") } if state.CreationTime.Unix() != newState.CreationTime.Unix() { t.Fatalf("creation time doesn't match") } }