// TstRunWithManagerUnlocked calls the given callback with the manager unlocked, // and locks it again before returning. func TstRunWithManagerUnlocked(t *testing.T, mgr *waddrmgr.Manager, callback func()) { if err := mgr.Unlock(privPassphrase); err != nil { t.Fatal(err) } defer mgr.Lock() callback() }
// getRedeemScript returns the redeem script for the given P2SH address. It must // be called with the manager unlocked. func getRedeemScript(mgr *waddrmgr.Manager, addr *btcutil.AddressScriptHash) ([]byte, error) { address, err := mgr.Address(addr) if err != nil { return nil, err } return address.(waddrmgr.ManagedScriptAddress).Script() }
// convertLegacyKeystore converts all of the addresses in the passed legacy // key store to the new waddrmgr.Manager format. Both the legacy keystore and // the new manager must be unlocked. func convertLegacyKeystore(legacyKeyStore *keystore.Store, manager *waddrmgr.Manager) error { netParams := legacyKeyStore.Net() blockStamp := waddrmgr.BlockStamp{ Height: 0, Hash: *netParams.GenesisHash, } for _, walletAddr := range legacyKeyStore.ActiveAddresses() { switch addr := walletAddr.(type) { case keystore.PubKeyAddress: privKey, err := addr.PrivKey() if err != nil { fmt.Printf("WARN: Failed to obtain private key "+ "for address %v: %v\n", addr.Address(), err) continue } wif, err := btcutil.NewWIF((*btcec.PrivateKey)(privKey), netParams, addr.Compressed()) if err != nil { fmt.Printf("WARN: Failed to create wallet "+ "import format for address %v: %v\n", addr.Address(), err) continue } _, err = manager.ImportPrivateKey(wif, &blockStamp) if err != nil { fmt.Printf("WARN: Failed to import private "+ "key for address %v: %v\n", addr.Address(), err) continue } case keystore.ScriptAddress: _, err := manager.ImportScript(addr.Script(), &blockStamp) if err != nil { fmt.Printf("WARN: Failed to import "+ "pay-to-script-hash script for "+ "address %v: %v\n", addr.Address(), err) continue } default: fmt.Printf("WARN: Skipping unrecognized legacy "+ "keystore type: %T\n", addr) continue } } return nil }
func encryptKeys(keys []string, mgr *waddrmgr.Manager, keyType waddrmgr.CryptoKeyType) ([][]byte, error) { encryptedKeys := make([][]byte, len(keys)) var err error for i, key := range keys { if key == "" { encryptedKeys[i] = nil } else { encryptedKeys[i], err = mgr.Encrypt(keyType, []byte(key)) } if err != nil { return nil, err } } return encryptedKeys, nil }
// signMultiSigUTXO signs the P2SH UTXO with the given index by constructing a // script containing all given signatures plus the redeem (multi-sig) script. The // redeem script is obtained by looking up the address of the given P2SH pkScript // on the address manager. // The order of the signatures must match that of the public keys in the multi-sig // script as OP_CHECKMULTISIG expects that. // This function must be called with the manager unlocked. func signMultiSigUTXO(mgr *waddrmgr.Manager, tx *wire.MsgTx, idx int, pkScript []byte, sigs []RawSig) error { class, addresses, _, err := txscript.ExtractPkScriptAddrs(pkScript, mgr.ChainParams()) if err != nil { return newError(ErrTxSigning, "unparseable pkScript", err) } if class != txscript.ScriptHashTy { return newError(ErrTxSigning, fmt.Sprintf("pkScript is not P2SH: %s", class), nil) } redeemScript, err := getRedeemScript(mgr, addresses[0].(*btcutil.AddressScriptHash)) if err != nil { return newError(ErrTxSigning, "unable to retrieve redeem script", err) } class, _, nRequired, err := txscript.ExtractPkScriptAddrs(redeemScript, mgr.ChainParams()) if err != nil { return newError(ErrTxSigning, "unparseable redeem script", err) } if class != txscript.MultiSigTy { return newError(ErrTxSigning, fmt.Sprintf("redeem script is not multi-sig: %v", class), nil) } if len(sigs) < nRequired { errStr := fmt.Sprintf("not enough signatures; need %d but got only %d", nRequired, len(sigs)) return newError(ErrTxSigning, errStr, nil) } // Construct the unlocking script. // Start with an OP_0 because of the bug in bitcoind, then add nRequired signatures. unlockingScript := txscript.NewScriptBuilder().AddOp(txscript.OP_FALSE) for _, sig := range sigs[:nRequired] { unlockingScript.AddData(sig) } // Combine the redeem script and the unlocking script to get the actual signature script. sigScript := unlockingScript.AddData(redeemScript) script, err := sigScript.Script() if err != nil { return newError(ErrTxSigning, "error building sigscript", err) } tx.TxIn[idx].SignatureScript = script if err := validateSigScript(tx, idx, pkScript); err != nil { return err } return nil }
// signMsgTx sets the SignatureScript for every item in msgtx.TxIn. // It must be called every time a msgtx is changed. // Only P2PKH outputs are supported at this point. func signMsgTx(msgtx *wire.MsgTx, prevOutputs []wtxmgr.Credit, mgr *waddrmgr.Manager, chainParams *chaincfg.Params) error { if len(prevOutputs) != len(msgtx.TxIn) { return fmt.Errorf( "Number of prevOutputs (%d) does not match number of tx inputs (%d)", len(prevOutputs), len(msgtx.TxIn)) } for i, output := range prevOutputs { // Errors don't matter here, as we only consider the // case where len(addrs) == 1. _, addrs, _, _ := txscript.ExtractPkScriptAddrs(output.PkScript, chainParams) if len(addrs) != 1 { continue } apkh, ok := addrs[0].(*btcutil.AddressPubKeyHash) if !ok { return ErrUnsupportedTransactionType } ai, err := mgr.Address(apkh) if err != nil { return fmt.Errorf("cannot get address info: %v", err) } pka := ai.(waddrmgr.ManagedPubKeyAddress) privkey, err := pka.PrivKey() if err != nil { return fmt.Errorf("cannot get private key: %v", err) } sigscript, err := txscript.SignatureScript(msgtx, i, output.PkScript, txscript.SigHashAll, privkey, ai.Compressed()) if err != nil { return fmt.Errorf("cannot create sigscript: %s", err) } msgtx.TxIn[i].SignatureScript = sigscript } return nil }
// Decode... func (o *OpenChannel) Decode(b io.Reader, addrManager *waddrmgr.Manager) error { var scratch [8]byte if _, err := b.Read(o.TheirLNID[:]); err != nil { return err } if _, err := b.Read(o.ChanID[:]); err != nil { return err } if _, err := b.Read(scratch[:]); err != nil { return err } o.MinFeePerKb = btcutil.Amount(endian.Uint64(scratch[:])) // nonce + serPrivKey + mac var encryptedPriv [24 + 32 + 16]byte if _, err := b.Read(encryptedPriv[:]); err != nil { return err } decryptedPriv, err := addrManager.Decrypt(waddrmgr.CKTPrivate, encryptedPriv[:]) if err != nil { return err } o.OurCommitKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), decryptedPriv) var serPubKey [33]byte if _, err := b.Read(serPubKey[:]); err != nil { return err } o.TheirCommitKey, err = btcec.ParsePubKey(serPubKey[:], btcec.S256()) if err != nil { return err } if _, err := b.Read(scratch[:]); err != nil { return err } o.Capacity = btcutil.Amount(endian.Uint64(scratch[:])) if _, err := b.Read(scratch[:]); err != nil { return err } o.OurBalance = btcutil.Amount(endian.Uint64(scratch[:])) if _, err := b.Read(scratch[:]); err != nil { return err } o.TheirBalance = btcutil.Amount(endian.Uint64(scratch[:])) o.TheirCommitTx = wire.NewMsgTx() if err := o.TheirCommitTx.Deserialize(b); err != nil { return err } o.OurCommitTx = wire.NewMsgTx() if err := o.OurCommitTx.Deserialize(b); err != nil { return err } o.FundingTx = wire.NewMsgTx() if err := o.FundingTx.Deserialize(b); err != nil { return err } if _, err := b.Read(encryptedPriv[:]); err != nil { return err } decryptedPriv, err = addrManager.Decrypt(waddrmgr.CKTPrivate, encryptedPriv[:]) if err != nil { return err } o.MultiSigKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), decryptedPriv) var redeemScript [71]byte if _, err := b.Read(redeemScript[:]); err != nil { return err } o.FundingRedeemScript = redeemScript[:] if _, err := b.Read(o.TheirCurrentRevocation[:]); err != nil { return err } var addr [34]byte if _, err := b.Read(addr[:]); err != nil { return err } o.OurDeliveryAddress, err = btcutil.DecodeAddress(string(addr[:]), ActiveNetParams) if err != nil { return err } if _, err := b.Read(addr[:]); err != nil { return err } o.TheirDeliveryAddress, err = btcutil.DecodeAddress(string(addr[:]), ActiveNetParams) if err != nil { return err } if err := binary.Read(b, endian, &o.CsvDelay); err != nil { return err } if err := binary.Read(b, endian, &o.NumUpdates); err != nil { return err } if err := binary.Read(b, endian, &o.TotalSatoshisSent); err != nil { return err } if err := binary.Read(b, endian, &o.TotalSatoshisReceived); err != nil { return err } var unix int64 if err := binary.Read(b, endian, &unix); err != nil { return err } o.CreationTime = time.Unix(unix, 0) return nil }
// Encode... // TODO(roasbeef): checksum func (o *OpenChannel) Encode(b io.Writer, addrManager *waddrmgr.Manager) error { if _, err := b.Write(o.TheirLNID[:]); err != nil { return err } if _, err := b.Write(o.ChanID[:]); err != nil { return err } if err := binary.Write(b, endian, uint64(o.MinFeePerKb)); err != nil { return err } encryptedPriv, err := addrManager.Encrypt(waddrmgr.CKTPrivate, o.OurCommitKey.Serialize()) if err != nil { return err } if _, err := b.Write(encryptedPriv); err != nil { return err } if _, err := b.Write(o.TheirCommitKey.SerializeCompressed()); err != nil { return err } if err := binary.Write(b, endian, uint64(o.Capacity)); err != nil { return err } if err := binary.Write(b, endian, uint64(o.OurBalance)); err != nil { return err } if err := binary.Write(b, endian, uint64(o.TheirBalance)); err != nil { return err } if err := o.TheirCommitTx.Serialize(b); err != nil { return err } if err := o.OurCommitTx.Serialize(b); err != nil { return err } if err := o.FundingTx.Serialize(b); err != nil { return err } encryptedPriv, err = addrManager.Encrypt(waddrmgr.CKTPrivate, o.MultiSigKey.Serialize()) if err != nil { return err } if _, err := b.Write(encryptedPriv); err != nil { return err } if _, err := b.Write(o.FundingRedeemScript); err != nil { return err } if _, err := b.Write(o.TheirCurrentRevocation[:]); err != nil { return err } // TODO(roasbeef): serialize shachains if _, err := b.Write([]byte(o.OurDeliveryAddress.EncodeAddress())); err != nil { return err } if _, err := b.Write([]byte(o.TheirDeliveryAddress.EncodeAddress())); err != nil { return err } if err := binary.Write(b, endian, o.CsvDelay); err != nil { return err } if err := binary.Write(b, endian, o.NumUpdates); err != nil { return err } if err := binary.Write(b, endian, o.TotalSatoshisSent); err != nil { return err } if err := binary.Write(b, endian, o.TotalSatoshisReceived); err != nil { return err } if err := binary.Write(b, endian, o.CreationTime.Unix()); err != nil { return err } return nil }