From 154dc1af6698dbcd95460949ded26a1bbe8858f2 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 7 Sep 2020 18:02:42 +0200 Subject: [PATCH] lncli: allow final transaction as raw hex in PSBT funding flow --- cmd/lncli/cmd_open_channel.go | 68 ++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/cmd/lncli/cmd_open_channel.go b/cmd/lncli/cmd_open_channel.go index 412306ba..d6547de9 100644 --- a/cmd/lncli/cmd_open_channel.go +++ b/cmd/lncli/cmd_open_channel.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "context" "crypto/rand" "encoding/base64" @@ -11,6 +12,7 @@ import ( "strings" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnwallet/chanfunding" @@ -43,9 +45,9 @@ Base64 encoded PSBT: ` userMsgSign = ` PSBT verified by lnd, please continue the funding flow by signing the PSBT by all required parties/devices. Once the transaction is fully signed, paste it -again here. +again here either in base64 PSBT or hex encoded raw wire TX format. -Base64 encoded signed PSBT: ` +Signed base64 encoded PSBT or hex encoded raw wire TX: ` ) // TODO(roasbeef): change default number of confirmations @@ -505,7 +507,7 @@ func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient, return fmt.Errorf("reading from console "+ "failed: %v", err) } - psbt, err := base64.StdEncoding.DecodeString( + fundedPsbt, err := base64.StdEncoding.DecodeString( strings.TrimSpace(psbtBase64), ) if err != nil { @@ -515,7 +517,7 @@ func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient, verifyMsg := &lnrpc.FundingTransitionMsg{ Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{ PsbtVerify: &lnrpc.FundingPsbtVerify{ - FundedPsbt: psbt, + FundedPsbt: fundedPsbt, PendingChanId: pendingChanID[:], }, }, @@ -531,7 +533,7 @@ func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient, fmt.Print(userMsgSign) // Read the signed PSBT and send it to lnd. - psbtBase64, err = readLine(quit) + finalTxStr, err := readLine(quit) if err == io.EOF { return nil } @@ -539,22 +541,16 @@ func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient, return fmt.Errorf("reading from console "+ "failed: %v", err) } - psbt, err = base64.StdEncoding.DecodeString( - strings.TrimSpace(psbtBase64), + finalizeMsg, err := finalizeMsgFromString( + finalTxStr, pendingChanID[:], ) if err != nil { - return fmt.Errorf("base64 decode failed: %v", - err) + return err } - finalizeMsg := &lnrpc.FundingTransitionMsg{ - Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{ - PsbtFinalize: &lnrpc.FundingPsbtFinalize{ - SignedPsbt: psbt, - PendingChanId: pendingChanID[:], - }, - }, + transitionMsg := &lnrpc.FundingTransitionMsg{ + Trigger: finalizeMsg, } - err = sendFundingState(ctxc, ctx, finalizeMsg) + err = sendFundingState(ctxc, ctx, transitionMsg) if err != nil { return fmt.Errorf("finalizing PSBT funding "+ "flow failed: %v", err) @@ -686,3 +682,41 @@ func sendFundingState(cancelCtx context.Context, cliCtx *cli.Context, _, err := client.FundingStateStep(cancelCtx, msg) return err } + +// finalizeMsgFromString creates the final message for the PsbtFinalize step +// from either a hex encoded raw wire transaction or a base64 encoded PSBT +// packet. +func finalizeMsgFromString(tx string, + pendingChanID []byte) (*lnrpc.FundingTransitionMsg_PsbtFinalize, error) { + + rawTx, err := hex.DecodeString(strings.TrimSpace(tx)) + if err == nil { + // Hex decoding succeeded so we assume we have a raw wire format + // transaction. Let's submit that instead of a PSBT packet. + tx := &wire.MsgTx{} + err := tx.Deserialize(bytes.NewReader(rawTx)) + if err != nil { + return nil, fmt.Errorf("deserializing as raw wire "+ + "transaction failed: %v", err) + } + return &lnrpc.FundingTransitionMsg_PsbtFinalize{ + PsbtFinalize: &lnrpc.FundingPsbtFinalize{ + FinalRawTx: rawTx, + PendingChanId: pendingChanID, + }, + }, nil + } + + // If the string isn't a hex encoded transaction, we assume it must be + // a base64 encoded PSBT packet. + psbtBytes, err := base64.StdEncoding.DecodeString(strings.TrimSpace(tx)) + if err != nil { + return nil, fmt.Errorf("base64 decode failed: %v", err) + } + return &lnrpc.FundingTransitionMsg_PsbtFinalize{ + PsbtFinalize: &lnrpc.FundingPsbtFinalize{ + SignedPsbt: psbtBytes, + PendingChanId: pendingChanID, + }, + }, nil +}