Merge pull request #5083 from guggero/psbt-size-fix

lncli: allow PSBT to be read from file
This commit is contained in:
Oliver Gugger 2021-03-10 23:02:02 +01:00 committed by GitHub
commit c623d21bd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 8 deletions

View File

@ -8,6 +8,8 @@ import (
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"strings"
@ -39,14 +41,23 @@ DO NOT PUBLISH the finished transaction by yourself or with another tool.
lnd MUST publish it in the proper funding flow order OR THE FUNDS CAN BE LOST!
Paste the funded PSBT here to continue the funding flow.
Base64 encoded PSBT: `
If your PSBT is very long (specifically, more than 4096 characters), please save
it to a file and paste the full file path here instead as some terminals will
truncate the pasted text if it's too long.
Base64 encoded PSBT (or path to text file): `
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 either in base64 PSBT or hex encoded raw wire TX format.
Signed base64 encoded PSBT or hex encoded raw wire TX: `
Signed base64 encoded PSBT or hex encoded raw wire TX (or path to text file): `
// psbtMaxFileSize is the maximum file size we allow a PSBT file to be
// in case we want to read a PSBT from a file. This is mainly to protect
// the user from choosing a large file by accident and running into out
// of memory issues or other weird errors.
psbtMaxFileSize = 1024 * 1024
)
// TODO(roasbeef): change default number of confirmations
@ -506,13 +517,13 @@ func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient,
// Read the user's response and send it to the server to
// verify everything's correct before anything is
// signed.
psbtBase64, err := readLine(quit)
psbtBase64, err := readTerminalOrFile(quit)
if err == io.EOF {
return nil
}
if err != nil {
return fmt.Errorf("reading from console "+
"failed: %v", err)
return fmt.Errorf("reading from terminal or "+
"file failed: %v", err)
}
fundedPsbt, err := base64.StdEncoding.DecodeString(
strings.TrimSpace(psbtBase64),
@ -540,13 +551,13 @@ func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient,
fmt.Print(userMsgSign)
// Read the signed PSBT and send it to lnd.
finalTxStr, err := readLine(quit)
finalTxStr, err := readTerminalOrFile(quit)
if err == io.EOF {
return nil
}
if err != nil {
return fmt.Errorf("reading from console "+
"failed: %v", err)
return fmt.Errorf("reading from terminal or "+
"file failed: %v", err)
}
finalizeMsg, err := finalizeMsgFromString(
finalTxStr, pendingChanID[:],
@ -635,6 +646,60 @@ func printChanPending(update *lnrpc.OpenStatusUpdate_ChanPending) error {
return nil
}
// readTerminalOrFile reads a single line from the terminal. If the line read is
// short enough to be a file and a file with that exact name exists, the content
// of that file is read and returned as a string. If the content is longer or no
// file exists, the string read from the terminal is returned directly. This
// function can be used to circumvent the N_TTY_BUF_SIZE kernel parameter that
// prevents pasting more than 4096 characters (on most systems) into a terminal.
func readTerminalOrFile(quit chan struct{}) (string, error) {
maybeFile, err := readLine(quit)
if err != nil {
return "", err
}
// Absolute file paths normally can't be longer than 255 characters so
// we don't even check if it's a file in that case.
if len(maybeFile) > 255 {
return maybeFile, nil
}
// It might be a file since the length is small enough. Calling os.Stat
// should be safe with any arbitrary input as it will only query info
// about the file, not open or execute it directly.
stat, err := os.Stat(maybeFile)
// The file doesn't exist, we must assume this wasn't a file path after
// all.
if err != nil && os.IsNotExist(err) {
return maybeFile, nil
}
// Some other error, perhaps access denied or something similar, let's
// surface that to the user.
if err != nil {
return "", err
}
// Make sure we don't read a huge file by accident which might lead to
// undesired side effects. Even very large PSBTs should still only be a
// few hundred kilobytes so it makes sense to put a cap here.
if stat.Size() > psbtMaxFileSize {
return "", fmt.Errorf("error reading file %s: size of %d "+
"bytes exceeds max PSBT file size of %d", maybeFile,
stat.Size(), psbtMaxFileSize)
}
// If it's a path to an existing file and it's small enough, let's try
// to read its content now.
content, err := ioutil.ReadFile(maybeFile)
if err != nil {
return "", err
}
return string(content), nil
}
// readLine reads a line from standard in but does not block in case of a
// system interrupt like syscall.SIGINT (Ctrl+C).
func readLine(quit chan struct{}) (string, error) {

View File

@ -76,6 +76,7 @@
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: router shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: unable add proof to the channel chanID=<hex>: edge marked as zombie
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: unable add proof to the channel chanID=<hex>: edge not found
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: unable to register for confirmation of ChannelPoint(<chan_point>): chain notifier shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: error sending channel announcement: gossiper is shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: error sending channel announcement: router shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: funding manager shutting down