lnwallet: segwit-ify all scripts and signing utils
This commit is contained in:
parent
163eb8dcb8
commit
eeb2887fe9
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user