mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-26 17:52:25 +01:00
Merge pull request #7668 from shaurya947/open-channel-memo
multi: accept memo note when opening channel
This commit is contained in:
commit
ac3e7be9a0
@ -220,6 +220,10 @@ const (
|
||||
// A tlv type definition used to serialize and deserialize the
|
||||
// confirmed ShortChannelID for a zero-conf channel.
|
||||
realScidType tlv.Type = 4
|
||||
|
||||
// A tlv type definition used to serialize and deserialize the
|
||||
// Memo for the channel channel.
|
||||
channelMemoType tlv.Type = 5
|
||||
)
|
||||
|
||||
// indexStatus is an enum-like type that describes what state the
|
||||
@ -818,6 +822,10 @@ type OpenChannel struct {
|
||||
// default ShortChannelID. This is only set for zero-conf channels.
|
||||
confirmedScid lnwire.ShortChannelID
|
||||
|
||||
// Memo is any arbitrary information we wish to store locally about the
|
||||
// channel that will be useful to our future selves.
|
||||
Memo []byte
|
||||
|
||||
// TODO(roasbeef): eww
|
||||
Db *ChannelStateDB
|
||||
|
||||
@ -3642,6 +3650,7 @@ func putChanInfo(chanBucket kvdb.RwBucket, channel *OpenChannel) error {
|
||||
initialRemoteBalanceType, &remoteBalance,
|
||||
),
|
||||
MakeScidRecord(realScidType, &channel.confirmedScid),
|
||||
tlv.MakePrimitiveRecord(channelMemoType, &channel.Memo),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -3839,10 +3848,11 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Create balance fields in uint64.
|
||||
// Create balance fields in uint64, and Memo field as byte slice.
|
||||
var (
|
||||
localBalance uint64
|
||||
remoteBalance uint64
|
||||
memo []byte
|
||||
)
|
||||
|
||||
// Create the tlv stream.
|
||||
@ -3859,6 +3869,7 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error {
|
||||
initialRemoteBalanceType, &remoteBalance,
|
||||
),
|
||||
MakeScidRecord(realScidType, &channel.confirmedScid),
|
||||
tlv.MakePrimitiveRecord(channelMemoType, &memo),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -3872,6 +3883,11 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error {
|
||||
channel.InitialLocalBalance = lnwire.MilliSatoshi(localBalance)
|
||||
channel.InitialRemoteBalance = lnwire.MilliSatoshi(remoteBalance)
|
||||
|
||||
// Attach the memo field if non-empty.
|
||||
if len(memo) > 0 {
|
||||
channel.Memo = memo
|
||||
}
|
||||
|
||||
channel.Packager = NewChannelPackager(channel.ShortChannelID)
|
||||
|
||||
// Finally, read the optional shutdown scripts.
|
||||
|
@ -93,7 +93,12 @@ var openChannelCommand = cli.Command{
|
||||
|
||||
One can manually set the fee to be used for the funding transaction via
|
||||
either the --conf_target or --sat_per_vbyte arguments. This is
|
||||
optional.`,
|
||||
optional.
|
||||
|
||||
One can also specify a short string memo to record some useful
|
||||
information about the channel using the --memo argument. This is stored
|
||||
locally only, and is purely for reference. It has no bearing on the
|
||||
channel's operation. Max allowed length is 500 characters.`,
|
||||
ArgsUsage: "node-key local-amt push-amt",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
@ -257,6 +262,14 @@ var openChannelCommand = cli.Command{
|
||||
"payment. If not specified, a default of 1% " +
|
||||
"of the channel capacity will be used.",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "memo",
|
||||
Usage: `(optional) a note-to-self containing some useful
|
||||
information about the channel. This is stored
|
||||
locally only, and is purely for reference. It
|
||||
has no bearing on the channel's operation. Max
|
||||
allowed length is 500 characters`,
|
||||
},
|
||||
},
|
||||
Action: actionDecorator(openChannel),
|
||||
}
|
||||
@ -300,6 +313,7 @@ func openChannel(ctx *cli.Context) error {
|
||||
ScidAlias: ctx.Bool("scid_alias"),
|
||||
RemoteChanReserveSat: ctx.Uint64("remote_reserve_sats"),
|
||||
FundMax: ctx.Bool("fundmax"),
|
||||
Memo: ctx.String("memo"),
|
||||
}
|
||||
|
||||
switch {
|
||||
|
@ -40,6 +40,11 @@ package](https://github.com/lightningnetwork/lnd/pull/7356)
|
||||
and `--protocol.custom-invoice` flags to set feature bits for various feature
|
||||
"sets", as defined in [BOLT 9](https://github.com/lightning/bolts/blob/master/09-features.md).
|
||||
|
||||
* `OpenChannel` now accepts an [optional `memo`
|
||||
argument](https://github.com/lightningnetwork/lnd/pull/7668) for specifying
|
||||
a helpful note-to-self containing arbitrary useful information about the
|
||||
channel.
|
||||
|
||||
## Misc
|
||||
|
||||
* [Generate default macaroons
|
||||
|
@ -291,6 +291,10 @@ type InitFundingMsg struct {
|
||||
// support explicit channel type negotiation.
|
||||
ChannelType *lnwire.ChannelType
|
||||
|
||||
// Memo is any arbitrary information we wish to store locally about the
|
||||
// channel that will be useful to our future selves.
|
||||
Memo []byte
|
||||
|
||||
// Updates is a channel which updates to the opening status of the
|
||||
// channel are sent on.
|
||||
Updates chan *lnrpc.OpenStatusUpdate
|
||||
@ -4137,6 +4141,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
||||
ZeroConf: zeroConf,
|
||||
OptionScidAlias: scid,
|
||||
ScidAliasFeature: scidFeatureVal,
|
||||
Memo: msg.Memo,
|
||||
}
|
||||
|
||||
reservation, err := f.cfg.Wallet.InitChannelReservation(req)
|
||||
|
@ -2,6 +2,7 @@ package itest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
@ -373,16 +374,32 @@ func runBasicChannelCreationAndUpdates(ht *lntest.HarnessTest,
|
||||
aliceChanSub := alice.RPC.SubscribeChannelEvents()
|
||||
|
||||
// Open the channels between Alice and Bob, asserting that the channels
|
||||
// have been properly opened on-chain.
|
||||
// have been properly opened on-chain. We also attach the optional Memo
|
||||
// argument to one of the channels so we can test that it can be
|
||||
// retrieved correctly when querying the created channel.
|
||||
chanPoints := make([]*lnrpc.ChannelPoint, numChannels)
|
||||
openChannelParams := []lntest.OpenChannelParams{
|
||||
{Amt: amount, Memo: "bob is a good peer"},
|
||||
{Amt: amount},
|
||||
}
|
||||
for i := 0; i < numChannels; i++ {
|
||||
chanPoints[i] = ht.OpenChannel(
|
||||
alice, bob, lntest.OpenChannelParams{
|
||||
Amt: amount,
|
||||
},
|
||||
alice, bob, openChannelParams[i],
|
||||
)
|
||||
}
|
||||
|
||||
// Alice should see the memo when retrieving the first channel.
|
||||
channel := ht.QueryChannelByChanPoint(alice, chanPoints[0])
|
||||
require.Equal(ht, "bob is a good peer", channel.Memo)
|
||||
|
||||
// Bob shouldn't see the memo since it's for Alice only.
|
||||
channel = ht.QueryChannelByChanPoint(bob, chanPoints[0])
|
||||
require.Empty(ht, channel.Memo, "Memo is not empty")
|
||||
|
||||
// The second channel doesn't have a memo.
|
||||
channel = ht.QueryChannelByChanPoint(alice, chanPoints[1])
|
||||
require.Empty(ht, channel.Memo, "Memo is not empty")
|
||||
|
||||
// Since each of the channels just became open, Bob and Alice should
|
||||
// each receive an open and an active notification for each channel.
|
||||
const numExpectedOpenUpdates = 3 * numChannels
|
||||
@ -445,6 +462,16 @@ func runBasicChannelCreationAndUpdates(ht *lntest.HarnessTest,
|
||||
}
|
||||
}
|
||||
|
||||
// If Bob now tries to open a channel with an invalid memo, reject it.
|
||||
invalidMemo := strings.Repeat("a", 501)
|
||||
params := lntest.OpenChannelParams{
|
||||
Amt: funding.MaxBtcFundingAmount,
|
||||
Memo: invalidMemo,
|
||||
}
|
||||
expErr := fmt.Errorf("provided memo (%s) is of length 501, exceeds 500",
|
||||
invalidMemo)
|
||||
ht.OpenChannelAssertErr(bob, alice, params, expErr)
|
||||
|
||||
// verifyCloseUpdatesReceived is used to verify that Alice and Bob
|
||||
// receive the correct channel updates in order.
|
||||
const numExpectedCloseUpdates = 3 * numChannels
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1545,6 +1545,13 @@ message Channel {
|
||||
|
||||
// This is the peer SCID alias.
|
||||
uint64 peer_scid_alias = 35 [jstype = JS_STRING];
|
||||
|
||||
/*
|
||||
An optional note-to-self to go along with the channel containing some
|
||||
useful information. This is only ever stored locally and in no way impacts
|
||||
the channel's operation.
|
||||
*/
|
||||
string memo = 36;
|
||||
}
|
||||
|
||||
message ListChannelsRequest {
|
||||
@ -2274,6 +2281,13 @@ message OpenChannelRequest {
|
||||
be zero and is ignored.
|
||||
*/
|
||||
bool fund_max = 26;
|
||||
|
||||
/*
|
||||
An optional note-to-self to go along with the channel containing some
|
||||
useful information. This is only ever stored locally and in no way impacts
|
||||
the channel's operation.
|
||||
*/
|
||||
string memo = 27;
|
||||
}
|
||||
message OpenStatusUpdate {
|
||||
oneof update {
|
||||
|
@ -3573,6 +3573,10 @@
|
||||
"type": "string",
|
||||
"format": "uint64",
|
||||
"description": "This is the peer SCID alias."
|
||||
},
|
||||
"memo": {
|
||||
"type": "string",
|
||||
"description": "An optional note-to-self to go along with the channel containing some\nuseful information. This is only ever stored locally and in no way impacts\nthe channel's operation."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -5820,6 +5824,10 @@
|
||||
"fund_max": {
|
||||
"type": "boolean",
|
||||
"description": "If set, then lnd will attempt to commit all the coins under control of the\ninternal wallet to open the channel, and the LocalFundingAmount field must\nbe zero and is ignored."
|
||||
},
|
||||
"memo": {
|
||||
"type": "string",
|
||||
"description": "An optional note-to-self to go along with the channel containing some\nuseful information. This is only ever stored locally and in no way impacts\nthe channel's operation."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -890,6 +890,12 @@ type OpenChannelParams struct {
|
||||
// FundMax is a boolean indicating whether the channel should be funded
|
||||
// with the maximum possible amount from the wallet.
|
||||
FundMax bool
|
||||
|
||||
// An optional note-to-self containing some useful information about the
|
||||
// channel. This is stored locally only, and is purely for reference. It
|
||||
// has no bearing on the channel's operation. Max allowed length is 500
|
||||
// characters.
|
||||
Memo string
|
||||
}
|
||||
|
||||
// prepareOpenChannel waits for both nodes to be synced to chain and returns an
|
||||
@ -931,6 +937,7 @@ func (h *HarnessTest) prepareOpenChannel(srcNode, destNode *node.HarnessNode,
|
||||
UseBaseFee: p.UseBaseFee,
|
||||
UseFeeRate: p.UseFeeRate,
|
||||
FundMax: p.FundMax,
|
||||
Memo: p.Memo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,6 +416,7 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
|
||||
Db: wallet.Cfg.Database,
|
||||
InitialLocalBalance: ourBalance,
|
||||
InitialRemoteBalance: theirBalance,
|
||||
Memo: req.Memo,
|
||||
},
|
||||
pushMSat: req.PushMSat,
|
||||
pendingChanID: req.PendingChanID,
|
||||
|
@ -179,6 +179,10 @@ type InitFundingReserveMsg struct {
|
||||
// negotiated.
|
||||
ScidAliasFeature bool
|
||||
|
||||
// Memo is any arbitrary information we wish to store locally about the
|
||||
// channel that will be useful to our future selves.
|
||||
Memo []byte
|
||||
|
||||
// err is a channel in which all errors will be sent across. Will be
|
||||
// nil if this initial set is successful.
|
||||
//
|
||||
|
11
rpcserver.go
11
rpcserver.go
@ -2169,6 +2169,15 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
||||
in.CommitmentType)
|
||||
}
|
||||
|
||||
// We limit the channel memo to be 500 characters long. This enforces
|
||||
// a reasonable upper bound on storage consumption. This also mimics
|
||||
// the length limit for the label of a TX.
|
||||
const maxMemoLength = 500
|
||||
if len(in.Memo) > maxMemoLength {
|
||||
return nil, fmt.Errorf("provided memo (%s) is of length %d, "+
|
||||
"exceeds %d", in.Memo, len(in.Memo), maxMemoLength)
|
||||
}
|
||||
|
||||
// Instruct the server to trigger the necessary events to attempt to
|
||||
// open a new channel. A stream is returned in place, this stream will
|
||||
// be used to consume updates of the state of the pending channel.
|
||||
@ -2194,6 +2203,7 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
||||
ChannelType: channelType,
|
||||
FundUpToMaxAmt: fundUpToMaxAmt,
|
||||
MinFundAmt: minFundAmt,
|
||||
Memo: []byte(in.Memo),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -4214,6 +4224,7 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel,
|
||||
PeerScidAlias: peerScidAlias.ToUint64(),
|
||||
ZeroConf: dbChannel.IsZeroConf(),
|
||||
ZeroConfConfirmedScid: dbChannel.ZeroConfRealScid().ToUint64(),
|
||||
Memo: string(dbChannel.Memo),
|
||||
// TODO: remove the following deprecated fields
|
||||
CsvDelay: uint32(dbChannel.LocalChanCfg.CsvDelay),
|
||||
LocalChanReserveSat: int64(dbChannel.LocalChanCfg.ChanReserve),
|
||||
|
Loading…
x
Reference in New Issue
Block a user