// spendNestedWitnessPubKey generates both a sigScript, and valid witness for // spending the passed pkScript with the specified input amount. The generated // sigScript is the version 0 p2wkh witness program corresponding to the queried // key. The witness stack is identical to that of one which spends a regular // p2wkh output. The input amount *must* correspond to the output value of the // previous pkScript, or else verification will fail since the new sighash // digest algorithm defined in BIP0143 includes the input value in the sighash. func spendNestedWitnessPubKeyHash(txIn *wire.TxIn, pkScript []byte, inputValue int64, chainParams *chaincfg.Params, secrets SecretsSource, tx *wire.MsgTx, hashCache *txscript.TxSigHashes, idx int) error { // First we need to obtain the key pair related to this p2sh output. _, addrs, _, err := txscript.ExtractPkScriptAddrs(pkScript, chainParams) if err != nil { return err } privKey, compressed, err := secrets.GetKey(addrs[0]) if err != nil { return err } pubKey := privKey.PubKey() var pubKeyHash []byte if compressed { pubKeyHash = btcutil.Hash160(pubKey.SerializeCompressed()) } else { pubKeyHash = btcutil.Hash160(pubKey.SerializeUncompressed()) } // Next, we'll generate a valid sigScript that'll allow us to spend // the p2sh output. The sigScript will contain only a single push of // the p2wkh witness program corresponding to the matching public key // of this address. p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, chainParams) if err != nil { return err } witnessProgram, err := txscript.PayToAddrScript(p2wkhAddr) if err != nil { return err } bldr := txscript.NewScriptBuilder() bldr.AddData(witnessProgram) sigScript, err := bldr.Script() if err != nil { return err } txIn.SignatureScript = sigScript // With the sigScript in place, we'll next generate the proper witness // that'll allow us to spend the p2wkh output. witnessScript, err := txscript.WitnessScript(tx, hashCache, idx, inputValue, witnessProgram, txscript.SigHashAll, privKey, compressed) if err != nil { return err } txIn.Witness = witnessScript return nil }
// signFundingTx generates signatures for all the inputs in the funding tx // belonging to Bob. // NOTE: This generates the full witness stack. func (b *bobNode) signFundingTx(fundingTx *wire.MsgTx) ([]*lnwallet.InputScript, error) { bobInputScripts := make([]*lnwallet.InputScript, 0, len(b.availableOutputs)) bobPkScript := b.changeOutputs[0].PkScript inputValue := int64(7e8) hashCache := txscript.NewTxSigHashes(fundingTx) for i, _ := range fundingTx.TxIn { // Alice has already signed this input. if fundingTx.TxIn[i].Witness != nil { continue } witness, err := txscript.WitnessScript(fundingTx, hashCache, i, inputValue, bobPkScript, txscript.SigHashAll, b.privKey, true) if err != nil { return nil, err } inputScript := &lnwallet.InputScript{Witness: witness} bobInputScripts = append(bobInputScripts, inputScript) } return bobInputScripts, nil }
// commitSpendNoDelay constructs a valid witness allowing a node to spend their // settled no-delay output on the counter-party's commitment transaction. func commitSpendNoDelay(commitScript []byte, outputAmt btcutil.Amount, commitPriv *btcec.PrivateKey, sweepTx *wire.MsgTx) (wire.TxWitness, error) { // This is just a regular p2wkh spend which looks something like: // * witness: <sig> <pubkey> hashCache := txscript.NewTxSigHashes(sweepTx) witness, err := txscript.WitnessScript(sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, commitPriv, true) if err != nil { return nil, err } return wire.TxWitness(witness), nil }
// spendWitnessKeyHash generates, and sets a valid witness for spending the // passed pkScript with the specified input amount. The input amount *must* // correspond to the output value of the previous pkScript, or else verification // will fail since the new sighash digest algorithm defined in BIP0143 includes // the input value in the sighash. func spendWitnessKeyHash(txIn *wire.TxIn, pkScript []byte, inputValue int64, chainParams *chaincfg.Params, secrets SecretsSource, tx *wire.MsgTx, hashCache *txscript.TxSigHashes, idx int) error { // First obtain the key pair associated with this p2wkh address. _, addrs, _, err := txscript.ExtractPkScriptAddrs(pkScript, chainParams) if err != nil { return err } privKey, compressed, err := secrets.GetKey(addrs[0]) if err != nil { return err } pubKey := privKey.PubKey() // Once we have the key pair, generate a p2wkh address type, respecting // the compression type of the generated key. var pubKeyHash []byte if compressed { pubKeyHash = btcutil.Hash160(pubKey.SerializeCompressed()) } else { pubKeyHash = btcutil.Hash160(pubKey.SerializeUncompressed()) } p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, chainParams) if err != nil { return err } // With the concrete address type, we can now generate the // corresponding witness program to be used to generate a valid witness // which will allow us to spend this output. witnessProgram, err := txscript.PayToAddrScript(p2wkhAddr) if err != nil { return err } witnessScript, err := txscript.WitnessScript(tx, hashCache, idx, inputValue, witnessProgram, txscript.SigHashAll, privKey, true) if err != nil { return err } txIn.Witness = witnessScript return nil }
// SendCoins does send coins, but it's very rudimentary // wit makes it into p2wpkh. Which is not yet spendable. func (s *SPVCon) SendCoins(adrs []btcutil.Address, sendAmts []int64) error { if len(adrs) != len(sendAmts) { return fmt.Errorf("%d addresses and %d amounts", len(adrs), len(sendAmts)) } var err error var score, totalSend, fee int64 dustCutoff := int64(20000) // below this amount, just give to miners satPerByte := int64(80) // satoshis per byte fee; have as arg later rawUtxos, err := s.TS.GetAllUtxos() if err != nil { return err } var allUtxos SortableUtxoSlice // start with utxos sorted by value. for _, utxo := range rawUtxos { score += utxo.Value allUtxos = append(allUtxos, *utxo) } // smallest and unconfirmed last (because it's reversed) sort.Sort(sort.Reverse(allUtxos)) // sort.Reverse(allUtxos) for _, amt := range sendAmts { totalSend += amt } // important rule in bitcoin, output total > input total is invalid. if totalSend > score { return fmt.Errorf("trying to send %d but %d available.", totalSend, score) } tx := wire.NewMsgTx() // make new tx // add non-change (arg) outputs for i, adr := range adrs { // make address script 76a914...88ac or 0014... outAdrScript, err := txscript.PayToAddrScript(adr) if err != nil { return err } // make user specified txout and add to tx txout := wire.NewTxOut(sendAmts[i], outAdrScript) tx.AddTxOut(txout) } // generate a utxo slice for your inputs var ins utxoSlice // add utxos until we've had enough nokori := totalSend // nokori is how much is needed on input side for _, utxo := range allUtxos { // skip unconfirmed. Or de-prioritize? // if utxo.AtHeight == 0 { // continue // } // yeah, lets add this utxo! ins = append(ins, utxo) // as we add utxos, fill in sigscripts // generate previous pkscripts (subscritpt?) for all utxos // then make txins with the utxo and prevpk, and insert them into the tx // these are all zeroed out during signing but it's an easy way to keep track var prevPKs []byte if utxo.IsWit { //tx.Flags = 0x01 wa, err := btcutil.NewAddressWitnessPubKeyHash( s.TS.Adrs[utxo.KeyIdx].PkhAdr.ScriptAddress(), s.TS.Param) prevPKs, err = txscript.PayToAddrScript(wa) if err != nil { return err } } else { // otherwise generate directly prevPKs, err = txscript.PayToAddrScript( s.TS.Adrs[utxo.KeyIdx].PkhAdr) if err != nil { return err } } tx.AddTxIn(wire.NewTxIn(&utxo.Op, prevPKs, nil)) nokori -= utxo.Value // if nokori is positive, don't bother checking fee yet. if nokori < 0 { fee = EstFee(tx, satPerByte) if nokori < -fee { // done adding utxos: nokori below negative est. fee break } } } // see if there's enough left to also add a change output changeOld, err := s.TS.NewAdr() // change is witnessy if err != nil { return err } changeAdr, err := btcutil.NewAddressWitnessPubKeyHash( changeOld.ScriptAddress(), s.TS.Param) if err != nil { return err } changeScript, err := txscript.PayToAddrScript(changeAdr) if err != nil { return err } changeOut := wire.NewTxOut(0, changeScript) tx.AddTxOut(changeOut) fee = EstFee(tx, satPerByte) changeOut.Value = -(nokori + fee) if changeOut.Value < dustCutoff { // remove last output (change) : not worth it tx.TxOut = tx.TxOut[:len(tx.TxOut)-1] } // sort utxos on the input side. use this instead of txsort // because we want to remember which keys are associated with which inputs sort.Sort(ins) // sort tx -- this only will change txouts since inputs are already sorted txsort.InPlaceSort(tx) // tx is ready for signing, sigStash := make([][]byte, len(ins)) witStash := make([][][]byte, len(ins)) // generate tx-wide hashCache for segwit stuff // middle index number doesn't matter for sighashAll. hCache := txscript.NewTxSigHashes(tx) for i, txin := range tx.TxIn { // pick key child, err := s.TS.rootPrivKey.Child( ins[i].KeyIdx + hdkeychain.HardenedKeyStart) if err != nil { return err } priv, err := child.ECPrivKey() if err != nil { return err } // This is where witness based sighash types need to happen // sign into stash if ins[i].IsWit { witStash[i], err = txscript.WitnessScript( tx, hCache, i, ins[i].Value, txin.SignatureScript, txscript.SigHashAll, priv, true) if err != nil { return err } } else { sigStash[i], err = txscript.SignatureScript( tx, i, txin.SignatureScript, txscript.SigHashAll, priv, true) if err != nil { return err } } } // swap sigs into sigScripts in txins for i, txin := range tx.TxIn { if sigStash[i] != nil { txin.SignatureScript = sigStash[i] } if witStash[i] != nil { txin.Witness = witStash[i] txin.SignatureScript = nil } } // fmt.Printf("tx: %s", TxToString(tx)) // buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) // send it out on the wire. hope it gets there. // we should deal with rejects. Don't yet. err = s.NewOutgoingTx(tx) if err != nil { return err } return nil }
func (s *SPVCon) SendOne(u Utxo, adr btcutil.Address) error { // fixed fee fee := int64(5000) sendAmt := u.Value - fee tx := wire.NewMsgTx() // make new tx // add single output outAdrScript, err := txscript.PayToAddrScript(adr) if err != nil { return err } // make user specified txout and add to tx txout := wire.NewTxOut(sendAmt, outAdrScript) tx.AddTxOut(txout) var prevPKs []byte if u.IsWit { //tx.Flags = 0x01 wa, err := btcutil.NewAddressWitnessPubKeyHash( s.TS.Adrs[u.KeyIdx].PkhAdr.ScriptAddress(), s.TS.Param) prevPKs, err = txscript.PayToAddrScript(wa) if err != nil { return err } } else { // otherwise generate directly prevPKs, err = txscript.PayToAddrScript( s.TS.Adrs[u.KeyIdx].PkhAdr) if err != nil { return err } } tx.AddTxIn(wire.NewTxIn(&u.Op, prevPKs, nil)) var sig []byte var wit [][]byte hCache := txscript.NewTxSigHashes(tx) child, err := s.TS.rootPrivKey.Child(u.KeyIdx + hdkeychain.HardenedKeyStart) if err != nil { return err } priv, err := child.ECPrivKey() if err != nil { return err } // This is where witness based sighash types need to happen // sign into stash if u.IsWit { wit, err = txscript.WitnessScript( tx, hCache, 0, u.Value, tx.TxIn[0].SignatureScript, txscript.SigHashAll, priv, true) if err != nil { return err } } else { sig, err = txscript.SignatureScript( tx, 0, tx.TxIn[0].SignatureScript, txscript.SigHashAll, priv, true) if err != nil { return err } } // swap sigs into sigScripts in txins if sig != nil { tx.TxIn[0].SignatureScript = sig } if wit != nil { tx.TxIn[0].Witness = wit tx.TxIn[0].SignatureScript = nil } return s.NewOutgoingTx(tx) }
// ComputeInputScript generates a complete InputIndex for the passed // transaction with the signature as defined within the passed SignDescriptor. // This method is capable of generating the proper input script for both // regular p2wkh output and p2wkh outputs nested within a regular p2sh output. // // This is a part of the WalletController interface. func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx, signDesc *lnwallet.SignDescriptor) (*lnwallet.InputScript, error) { outputScript := signDesc.Output.PkScript walletAddr, err := b.fetchOutputAddr(outputScript) if err != nil { return nil, nil } pka := walletAddr.(waddrmgr.ManagedPubKeyAddress) privKey, err := pka.PrivKey() if err != nil { return nil, err } var witnessProgram []byte inputScript := &lnwallet.InputScript{} // If we're spending p2wkh output nested within a p2sh output, then // we'll need to attach a sigScript in addition to witness data. switch { case pka.IsNestedWitness(): pubKey := privKey.PubKey() pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) // Next, we'll generate a valid sigScript that'll allow us to // spend the p2sh output. The sigScript will contain only a // single push of the p2wkh witness program corresponding to // the matching public key of this address. p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, b.netParams) if err != nil { return nil, err } witnessProgram, err = txscript.PayToAddrScript(p2wkhAddr) if err != nil { return nil, err } bldr := txscript.NewScriptBuilder() bldr.AddData(witnessProgram) sigScript, err := bldr.Script() if err != nil { return nil, err } inputScript.ScriptSig = sigScript // Otherwise, this is a regular p2wkh output, so we include the // witness program itself as the subscript to generate the proper // sighash digest. As part of the new sighash digest algorithm, the // p2wkh witness program will be expanded into a regular p2kh // script. default: witnessProgram = outputScript } // Generate a valid witness stack for the input. // TODO(roasbeef): adhere to passed HashType witnessScript, err := txscript.WitnessScript(tx, signDesc.SigHashes, signDesc.InputIndex, signDesc.Output.Value, witnessProgram, txscript.SigHashAll, privKey, true) if err != nil { return nil, err } inputScript.Witness = witnessScript return inputScript, nil }