lnwallet: segwit-ify all scripts and signing utils

This commit is contained in:
Olaoluwa Osuntokun 2016-05-03 19:45:32 -07:00
parent 163eb8dcb8
commit eeb2887fe9
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
2 changed files with 42 additions and 44 deletions

@ -81,7 +81,7 @@ func newLightningChannel(wallet *LightningWallet, events chainntnfs.ChainNotifie
lc.updateTotem <- struct{}{} lc.updateTotem <- struct{}{}
fundingTxId := state.FundingTx.TxSha() fundingTxId := state.FundingTx.TxSha()
fundingPkScript, err := scriptHashPkScript(state.FundingRedeemScript) fundingPkScript, err := witnessScriptHash(state.FundingRedeemScript)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -181,8 +181,6 @@ func (c *ChannelUpdate) VerifyNewCommitmentSigs(ourSig, theirSig []byte) error {
c.lnChannel.stateMtx.RLock() c.lnChannel.stateMtx.RLock()
defer c.lnChannel.stateMtx.RUnlock() defer c.lnChannel.stateMtx.RUnlock()
var err error
var scriptSig []byte
channelState := c.lnChannel.channelState channelState := c.lnChannel.channelState
// When initially generating the redeemScript, we sorted the serialized // When initially generating the redeemScript, we sorted the serialized
@ -192,15 +190,12 @@ func (c *ChannelUpdate) VerifyNewCommitmentSigs(ourSig, theirSig []byte) error {
redeemScript := channelState.FundingRedeemScript redeemScript := channelState.FundingRedeemScript
ourKey := channelState.OurCommitKey.PubKey().SerializeCompressed() ourKey := channelState.OurCommitKey.PubKey().SerializeCompressed()
theirKey := channelState.TheirCommitKey.SerializeCompressed() theirKey := channelState.TheirCommitKey.SerializeCompressed()
scriptSig, err = spendMultiSig(redeemScript, ourKey, ourSig, theirKey, theirSig) witness := spendMultiSig(redeemScript, ourKey, ourSig, theirKey, theirSig)
if err != nil {
return err
}
// Attach the scriptSig to our commitment transaction's only input, // Attach the scriptSig to our commitment transaction's only input,
// then validate that the scriptSig executes correctly. // then validate that the scriptSig executes correctly.
commitTx := c.ourPendingCommitTx commitTx := c.ourPendingCommitTx
commitTx.TxIn[0].SignatureScript = scriptSig commitTx.TxIn[0].Witness = witness
vm, err := txscript.NewEngine(c.lnChannel.fundingP2SH, commitTx, 0, vm, err := txscript.NewEngine(c.lnChannel.fundingP2SH, commitTx, 0,
txscript.StandardVerifyFlags, nil, nil, 0) txscript.StandardVerifyFlags, nil, nil, 0)
if err != nil { if err != nil {
@ -387,13 +382,13 @@ func (lc *LightningChannel) addHTLC(ourCommitTx, theirCommitTx *wire.MsgTx,
return nil return nil
} }
// Now that we have the redeem scripts, create the P2SH public key // Now that we have the redeem scripts, create the P2WSH public key
// script for each. // script for each.
senderP2SH, err := scriptHashPkScript(senderPKScript) senderP2SH, err := witnessScriptHash(senderPKScript)
if err != nil { if err != nil {
return nil return nil
} }
receiverP2SH, err := scriptHashPkScript(receiverPKScript) receiverP2SH, err := witnessScriptHash(receiverPKScript)
if err != nil { if err != nil {
return nil return nil
} }
@ -566,7 +561,7 @@ func createCommitTx(fundingOutput *wire.TxIn, selfKey, theirKey *btcec.PublicKey
if err != nil { if err != nil {
return nil, err return nil, err
} }
payToUsScriptHash, err := scriptHashPkScript(ourRedeemScript) payToUsScriptHash, err := witnessScriptHash(ourRedeemScript)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -578,7 +573,7 @@ func createCommitTx(fundingOutput *wire.TxIn, selfKey, theirKey *btcec.PublicKey
if err != nil { if err != nil {
return nil, err return nil, err
} }
payToThemScriptHash, err := scriptHashPkScript(theirRedeemScript) payToThemScriptHash, err := witnessScriptHash(theirRedeemScript)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -8,6 +8,7 @@ import (
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/fastsha256"
) )
var ( var (
@ -18,19 +19,20 @@ var (
OP_CHECKSEQUENCEVERIFY byte = txscript.OP_NOP3 OP_CHECKSEQUENCEVERIFY byte = txscript.OP_NOP3
) )
// scriptHashPkScript generates a pay-to-script-hash public key script paying // witnessScriptHash generates a pay-to-witness-script-hash public key script
// to the hash160 of the passed redeem script. // paying to a version 0 witness program paying to the passed redeem script.
func scriptHashPkScript(redeemScript []byte) ([]byte, error) { func witnessScriptHash(redeemScript []byte) ([]byte, error) {
bldr := txscript.NewScriptBuilder() bldr := txscript.NewScriptBuilder()
bldr.AddOp(txscript.OP_HASH160)
bldr.AddData(btcutil.Hash160(redeemScript)) bldr.AddOp(txscript.OP_0)
bldr.AddOp(txscript.OP_EQUAL) scriptHash := fastsha256.Sum256(redeemScript)
bldr.AddData(scriptHash[:])
return bldr.Script() return bldr.Script()
} }
// getFundingPkScript generates the non-p2sh'd multisig script for 2 of 2 // genMultiSigScript generates the non-p2sh'd multisig script for 2 of 2
// pubkeys. // pubkeys.
func genFundingPkScript(aPub, bPub []byte) ([]byte, error) { func genMultiSigScript(aPub, bPub []byte) ([]byte, error) {
if len(aPub) != 33 || len(bPub) != 33 { if len(aPub) != 33 || len(bPub) != 33 {
return nil, fmt.Errorf("Pubkey size error. Compressed pubkeys only") return nil, fmt.Errorf("Pubkey size error. Compressed pubkeys only")
} }
@ -52,23 +54,24 @@ func genFundingPkScript(aPub, bPub []byte) ([]byte, error) {
return bldr.Script() return bldr.Script()
} }
// fundMultiSigOut create the redeemScript for the funding transaction, and // genFundingPkScript creates a redeem script, and its matching p2wsh
// also a TxOut paying to the p2sh of the multi-sig redeemScript. Give it the // output for the funding transaction.
// two pubkeys and it'll give you the p2sh'd txout. You don't have to remember func genFundingPkScript(aPub, bPub []byte, amt int64) ([]byte, *wire.TxOut, error) {
// the p2sh preimage, as long as you remember the pubkeys involved. // As a sanity check, ensure that the passed amount is above zero.
func fundMultiSigOut(aPub, bPub []byte, amt int64) ([]byte, *wire.TxOut, error) { if amt <= 0 {
if amt < 0 {
return nil, nil, fmt.Errorf("can't create FundTx script with " + return nil, nil, fmt.Errorf("can't create FundTx script with " +
"negative coins") "zero, or negative coins")
} }
// p2shify // First, create the 2-of-2 multi-sig script itself.
redeemScript, err := genFundingPkScript(aPub, bPub) redeemScript, err := genMultiSigScript(aPub, bPub)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pkScript, err := scriptHashPkScript(redeemScript) // With the 2-of-2 script in had, generate a p2wsh script which pays
// to the funding script.
pkScript, err := witnessScriptHash(redeemScript)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -76,31 +79,31 @@ func fundMultiSigOut(aPub, bPub []byte, amt int64) ([]byte, *wire.TxOut, error)
return redeemScript, wire.NewTxOut(amt, pkScript), nil return redeemScript, wire.NewTxOut(amt, pkScript), nil
} }
// spendMultiSig generates the scriptSig required to redeem the 2-of-2 p2sh // spendMultiSig generates the witness stack required to redeem the 2-of-2 p2wsh
// multi-sig output. // multi-sig output.
func spendMultiSig(redeemScript, pubA, sigA, pubB, sigB []byte) ([]byte, error) { func spendMultiSig(redeemScript, pubA, sigA, pubB, sigB []byte) [][]byte {
bldr := txscript.NewScriptBuilder() witness := make([][]byte, 4)
// add a 0 for some multisig fun // When spending a p2wsh multi-sig script, rather than an OP_0, we add
bldr.AddOp(txscript.OP_0) // a nil stack element to eat the extra pop.
witness[0] = nil
// When initially generating the redeemScript, we sorted the serialized // When initially generating the redeemScript, we sorted the serialized
// public keys in descending order. So we do a quick comparison in order // public keys in descending order. So we do a quick comparison in order
// ensure the signatures appear on the Script Virual Machine stack in // ensure the signatures appear on the Script Virual Machine stack in
// the correct order. // the correct order.
if bytes.Compare(pubA, pubB) == -1 { if bytes.Compare(pubA, pubB) == -1 {
bldr.AddData(sigB) witness[1] = sigB
bldr.AddData(sigA) witness[2] = sigA
} else { } else {
bldr.AddData(sigA) witness[1] = sigA
bldr.AddData(sigB) witness[2] = sigB
} }
// preimage goes on AT THE ENDDDD // Finally, add the pre-image as the last witness element.
bldr.AddData(redeemScript) witness[3] = redeemScript
// that's all, get bytes return witness
return bldr.Script()
} }
// findScriptOutputIndex finds the index of the public key script output // findScriptOutputIndex finds the index of the public key script output