lnd/lnwallet/script_utils.go

102 lines
2.5 KiB
Go

package lnwallet
import (
"bytes"
"fmt"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
// scriptHashPkScript...
func scriptHashPkScript(scriptBytes []byte) ([]byte, error) {
bldr := txscript.NewScriptBuilder()
bldr.AddOp(txscript.OP_HASH160)
bldr.AddData(btcutil.Hash160(scriptBytes))
bldr.AddOp(txscript.OP_EQUAL)
return bldr.Script()
}
// getFundingPkScript generates the non-p2sh'd multisig script for 2 of 2
// pubkeys.
func genFundingPkScript(aPub, bPub []byte) ([]byte, error) {
if len(aPub) != 33 || len(bPub) != 33 {
return nil, fmt.Errorf("Pubkey size error. Compressed pubkeys only")
}
if bytes.Compare(aPub, bPub) == -1 { // swap to sort pubkeys if needed
aPub, bPub = bPub, aPub
}
bldr := txscript.NewScriptBuilder()
// Require 2 signatures, so from both of the pubkeys
bldr.AddOp(txscript.OP_2)
// add both pubkeys (sorted)
bldr.AddData(aPub)
bldr.AddData(bPub)
// 2 keys total. In case that wasn't obvious.
bldr.AddOp(txscript.OP_2)
// Good ol OP_CHECKMULTISIG. Don't forget the zero!
bldr.AddOp(txscript.OP_CHECKMULTISIG)
// get byte slice
return bldr.Script()
}
// fundMultiSigOut creates a TxOut for the funding transaction.
// Give it the two pubkeys and it'll give you the p2sh'd txout.
// You don't have to remember the p2sh preimage, as long as you remember the
// pubkeys involved.
func fundMultiSigOut(aPub, bPub []byte, amt int64) ([]byte, *wire.TxOut, error) {
if amt < 0 {
return nil, nil, fmt.Errorf("Can't create FundTx script with negative coins")
}
// p2shify
redeemScript, err := genFundingPkScript(aPub, bPub)
if err != nil {
return nil, nil, err
}
pkScript, err := scriptHashPkScript(redeemScript)
if err != nil {
return nil, nil, err
}
return redeemScript, wire.NewTxOut(amt, pkScript), nil
}
// the scriptsig to put on a P2SH input
func spendMultiSig(redeemScript, sigA, sigB []byte) ([]byte, error) {
bldr := txscript.NewScriptBuilder()
// add a 0 for some multisig fun
bldr.AddOp(txscript.OP_0)
// add sigA
bldr.AddData(sigA)
// add sigB
bldr.AddData(sigB)
// preimage goes on AT THE ENDDDD
bldr.AddData(redeemScript)
// that's all, get bytes
return bldr.Script()
}
// findScriptOutputIndex...
// only finds first matchin, assumes unique pkScripts
func findScriptOutputIndex(tx *wire.MsgTx, script []byte) (bool, uint32) {
found := false
index := uint32(0)
for i, txOut := range tx.TxOut {
if bytes.Equal(txOut.PkScript, script) {
found = true
index = uint32(i)
break
}
}
return found, index
}