mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 01:36:24 +01:00
Merge pull request #971 from vctt94/addMaxValueFlag
Add max value in flight flag
This commit is contained in:
commit
9e8c39d4a2
9 changed files with 881 additions and 770 deletions
|
@ -163,6 +163,11 @@ var openChannelCommand = cli.Command{
|
||||||
"as a base and add the new channel output to " +
|
"as a base and add the new channel output to " +
|
||||||
"it instead of creating a new, empty one.",
|
"it instead of creating a new, empty one.",
|
||||||
},
|
},
|
||||||
|
cli.Uint64Flag{
|
||||||
|
Name: "remote_max_value_in_flight_msat",
|
||||||
|
Usage: "(optional) the maximum value in msat that " +
|
||||||
|
"can be pending within the channel at any given time",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: actionDecorator(openChannel),
|
Action: actionDecorator(openChannel),
|
||||||
}
|
}
|
||||||
|
@ -184,13 +189,14 @@ func openChannel(ctx *cli.Context) error {
|
||||||
|
|
||||||
minConfs := int32(ctx.Uint64("min_confs"))
|
minConfs := int32(ctx.Uint64("min_confs"))
|
||||||
req := &lnrpc.OpenChannelRequest{
|
req := &lnrpc.OpenChannelRequest{
|
||||||
TargetConf: int32(ctx.Int64("conf_target")),
|
TargetConf: int32(ctx.Int64("conf_target")),
|
||||||
SatPerByte: ctx.Int64("sat_per_byte"),
|
SatPerByte: ctx.Int64("sat_per_byte"),
|
||||||
MinHtlcMsat: ctx.Int64("min_htlc_msat"),
|
MinHtlcMsat: ctx.Int64("min_htlc_msat"),
|
||||||
RemoteCsvDelay: uint32(ctx.Uint64("remote_csv_delay")),
|
RemoteCsvDelay: uint32(ctx.Uint64("remote_csv_delay")),
|
||||||
MinConfs: minConfs,
|
MinConfs: minConfs,
|
||||||
SpendUnconfirmed: minConfs == 0,
|
SpendUnconfirmed: minConfs == 0,
|
||||||
CloseAddress: ctx.String("close_address"),
|
CloseAddress: ctx.String("close_address"),
|
||||||
|
RemoteMaxValueInFlightMsat: ctx.Uint64("remote_max_value_in_flight_msat"),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -122,6 +122,7 @@ type reservationWithCtx struct {
|
||||||
// Constraints we require for the remote.
|
// Constraints we require for the remote.
|
||||||
remoteCsvDelay uint16
|
remoteCsvDelay uint16
|
||||||
remoteMinHtlc lnwire.MilliSatoshi
|
remoteMinHtlc lnwire.MilliSatoshi
|
||||||
|
remoteMaxValue lnwire.MilliSatoshi
|
||||||
|
|
||||||
updateMtx sync.RWMutex
|
updateMtx sync.RWMutex
|
||||||
lastUpdated time.Time
|
lastUpdated time.Time
|
||||||
|
@ -1376,7 +1377,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
||||||
// Generate our required constraints for the remote party.
|
// Generate our required constraints for the remote party.
|
||||||
remoteCsvDelay := f.cfg.RequiredRemoteDelay(amt)
|
remoteCsvDelay := f.cfg.RequiredRemoteDelay(amt)
|
||||||
chanReserve := f.cfg.RequiredRemoteChanReserve(amt, msg.DustLimit)
|
chanReserve := f.cfg.RequiredRemoteChanReserve(amt, msg.DustLimit)
|
||||||
maxValue := f.cfg.RequiredRemoteMaxValue(amt)
|
remoteMaxValue := f.cfg.RequiredRemoteMaxValue(amt)
|
||||||
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(amt)
|
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(amt)
|
||||||
minHtlc := f.cfg.DefaultMinHtlcIn
|
minHtlc := f.cfg.DefaultMinHtlcIn
|
||||||
|
|
||||||
|
@ -1392,6 +1393,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
||||||
chanAmt: amt,
|
chanAmt: amt,
|
||||||
remoteCsvDelay: remoteCsvDelay,
|
remoteCsvDelay: remoteCsvDelay,
|
||||||
remoteMinHtlc: minHtlc,
|
remoteMinHtlc: minHtlc,
|
||||||
|
remoteMaxValue: remoteMaxValue,
|
||||||
err: make(chan error, 1),
|
err: make(chan error, 1),
|
||||||
peer: fmsg.peer,
|
peer: fmsg.peer,
|
||||||
}
|
}
|
||||||
|
@ -1409,7 +1411,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
||||||
ChannelConfig: &channeldb.ChannelConfig{
|
ChannelConfig: &channeldb.ChannelConfig{
|
||||||
ChannelConstraints: channeldb.ChannelConstraints{
|
ChannelConstraints: channeldb.ChannelConstraints{
|
||||||
DustLimit: msg.DustLimit,
|
DustLimit: msg.DustLimit,
|
||||||
MaxPendingAmount: maxValue,
|
MaxPendingAmount: remoteMaxValue,
|
||||||
ChanReserve: chanReserve,
|
ChanReserve: chanReserve,
|
||||||
MinHTLC: minHtlc,
|
MinHTLC: minHtlc,
|
||||||
MaxAcceptedHtlcs: maxHtlcs,
|
MaxAcceptedHtlcs: maxHtlcs,
|
||||||
|
@ -1451,7 +1453,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
||||||
fundingAccept := lnwire.AcceptChannel{
|
fundingAccept := lnwire.AcceptChannel{
|
||||||
PendingChannelID: msg.PendingChannelID,
|
PendingChannelID: msg.PendingChannelID,
|
||||||
DustLimit: ourContribution.DustLimit,
|
DustLimit: ourContribution.DustLimit,
|
||||||
MaxValueInFlight: maxValue,
|
MaxValueInFlight: remoteMaxValue,
|
||||||
ChannelReserve: chanReserve,
|
ChannelReserve: chanReserve,
|
||||||
MinAcceptDepth: uint32(numConfsReq),
|
MinAcceptDepth: uint32(numConfsReq),
|
||||||
HtlcMinimum: minHtlc,
|
HtlcMinimum: minHtlc,
|
||||||
|
@ -1465,6 +1467,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
|
||||||
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
|
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
|
||||||
UpfrontShutdownScript: ourContribution.UpfrontShutdown,
|
UpfrontShutdownScript: ourContribution.UpfrontShutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fmsg.peer.SendMessage(true, &fundingAccept); err != nil {
|
if err := fmsg.peer.SendMessage(true, &fundingAccept); err != nil {
|
||||||
fndgLog.Errorf("unable to send funding response to peer: %v", err)
|
fndgLog.Errorf("unable to send funding response to peer: %v", err)
|
||||||
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
|
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
|
||||||
|
@ -1540,7 +1543,6 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
|
||||||
// here so we can properly commit their accepted constraints to the
|
// here so we can properly commit their accepted constraints to the
|
||||||
// reservation.
|
// reservation.
|
||||||
chanReserve := f.cfg.RequiredRemoteChanReserve(resCtx.chanAmt, msg.DustLimit)
|
chanReserve := f.cfg.RequiredRemoteChanReserve(resCtx.chanAmt, msg.DustLimit)
|
||||||
maxValue := f.cfg.RequiredRemoteMaxValue(resCtx.chanAmt)
|
|
||||||
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(resCtx.chanAmt)
|
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(resCtx.chanAmt)
|
||||||
|
|
||||||
// The remote node has responded with their portion of the channel
|
// The remote node has responded with their portion of the channel
|
||||||
|
@ -1552,7 +1554,7 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
|
||||||
ChannelConfig: &channeldb.ChannelConfig{
|
ChannelConfig: &channeldb.ChannelConfig{
|
||||||
ChannelConstraints: channeldb.ChannelConstraints{
|
ChannelConstraints: channeldb.ChannelConstraints{
|
||||||
DustLimit: msg.DustLimit,
|
DustLimit: msg.DustLimit,
|
||||||
MaxPendingAmount: maxValue,
|
MaxPendingAmount: resCtx.remoteMaxValue,
|
||||||
ChanReserve: chanReserve,
|
ChanReserve: chanReserve,
|
||||||
MinHTLC: resCtx.remoteMinHtlc,
|
MinHTLC: resCtx.remoteMinHtlc,
|
||||||
MaxAcceptedHtlcs: maxHtlcs,
|
MaxAcceptedHtlcs: maxHtlcs,
|
||||||
|
@ -3065,6 +3067,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
||||||
localAmt = msg.localFundingAmt
|
localAmt = msg.localFundingAmt
|
||||||
minHtlcIn = msg.minHtlcIn
|
minHtlcIn = msg.minHtlcIn
|
||||||
remoteCsvDelay = msg.remoteCsvDelay
|
remoteCsvDelay = msg.remoteCsvDelay
|
||||||
|
maxValue = msg.maxValueInFlight
|
||||||
)
|
)
|
||||||
|
|
||||||
// We'll determine our dust limit depending on which chain is active.
|
// We'll determine our dust limit depending on which chain is active.
|
||||||
|
@ -3198,6 +3201,11 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
||||||
minHtlcIn = f.cfg.DefaultMinHtlcIn
|
minHtlcIn = f.cfg.DefaultMinHtlcIn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no max value was specified, use the default one.
|
||||||
|
if maxValue == 0 {
|
||||||
|
maxValue = f.cfg.RequiredRemoteMaxValue(capacity)
|
||||||
|
}
|
||||||
|
|
||||||
// If a pending channel map for this peer isn't already created, then
|
// If a pending channel map for this peer isn't already created, then
|
||||||
// we create one, ultimately allowing us to track this pending
|
// we create one, ultimately allowing us to track this pending
|
||||||
// reservation within the target peer.
|
// reservation within the target peer.
|
||||||
|
@ -3211,6 +3219,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
||||||
chanAmt: capacity,
|
chanAmt: capacity,
|
||||||
remoteCsvDelay: remoteCsvDelay,
|
remoteCsvDelay: remoteCsvDelay,
|
||||||
remoteMinHtlc: minHtlcIn,
|
remoteMinHtlc: minHtlcIn,
|
||||||
|
remoteMaxValue: maxValue,
|
||||||
reservation: reservation,
|
reservation: reservation,
|
||||||
peer: msg.peer,
|
peer: msg.peer,
|
||||||
updates: msg.updates,
|
updates: msg.updates,
|
||||||
|
@ -3230,7 +3239,6 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
|
||||||
// policy to determine of required commitment constraints for the
|
// policy to determine of required commitment constraints for the
|
||||||
// remote party.
|
// remote party.
|
||||||
chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit)
|
chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit)
|
||||||
maxValue := f.cfg.RequiredRemoteMaxValue(capacity)
|
|
||||||
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(capacity)
|
maxHtlcs := f.cfg.RequiredRemoteMaxHTLCs(capacity)
|
||||||
|
|
||||||
fndgLog.Infof("Starting funding workflow with %v for pending_id(%x), "+
|
fndgLog.Infof("Starting funding workflow with %v for pending_id(%x), "+
|
||||||
|
|
|
@ -966,7 +966,8 @@ func assertAddedToRouterGraph(t *testing.T, alice, bob *testNode,
|
||||||
// advertised value will be checked against the other node's default min_htlc
|
// advertised value will be checked against the other node's default min_htlc
|
||||||
// value.
|
// value.
|
||||||
func assertChannelAnnouncements(t *testing.T, alice, bob *testNode,
|
func assertChannelAnnouncements(t *testing.T, alice, bob *testNode,
|
||||||
capacity btcutil.Amount, customMinHtlc ...lnwire.MilliSatoshi) {
|
capacity btcutil.Amount, customMinHtlc []lnwire.MilliSatoshi,
|
||||||
|
customMaxHtlc []lnwire.MilliSatoshi) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
// After the FundingLocked message is sent, Alice and Bob will each
|
// After the FundingLocked message is sent, Alice and Bob will each
|
||||||
|
@ -1019,21 +1020,28 @@ func assertChannelAnnouncements(t *testing.T, alice, bob *testNode,
|
||||||
minHtlc, m.HtlcMinimumMsat)
|
minHtlc, m.HtlcMinimumMsat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The MaxHTLC value should at this point
|
maxHtlc := alice.fundingMgr.cfg.RequiredRemoteMaxValue(
|
||||||
// _always_ be the same as the
|
capacity,
|
||||||
// maxValueInFlight capacity.
|
)
|
||||||
|
// We might expect a custom MaxHltc value.
|
||||||
|
if len(customMaxHtlc) > 0 {
|
||||||
|
if len(customMaxHtlc) != 2 {
|
||||||
|
t.Fatalf("only 0 or 2 custom " +
|
||||||
|
"min htlc values " +
|
||||||
|
"currently supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
maxHtlc = customMaxHtlc[j]
|
||||||
|
}
|
||||||
if m.MessageFlags != 1 {
|
if m.MessageFlags != 1 {
|
||||||
t.Fatalf("expected message flags to "+
|
t.Fatalf("expected message flags to "+
|
||||||
"be 1, was %v", m.MessageFlags)
|
"be 1, was %v", m.MessageFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
maxPendingMsat := alice.fundingMgr.cfg.RequiredRemoteMaxValue(
|
if maxHtlc != m.HtlcMaximumMsat {
|
||||||
capacity,
|
|
||||||
)
|
|
||||||
if maxPendingMsat != m.HtlcMaximumMsat {
|
|
||||||
t.Fatalf("expected ChannelUpdate to "+
|
t.Fatalf("expected ChannelUpdate to "+
|
||||||
"advertise max HTLC %v, had %v",
|
"advertise max HTLC %v, had %v",
|
||||||
maxPendingMsat,
|
maxHtlc,
|
||||||
m.HtlcMaximumMsat)
|
m.HtlcMaximumMsat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,7 +1227,7 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Check that the state machine is updated accordingly
|
// Check that the state machine is updated accordingly
|
||||||
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
||||||
|
@ -1371,7 +1379,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Check that the state machine is updated accordingly
|
// Check that the state machine is updated accordingly
|
||||||
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
||||||
|
@ -1509,7 +1517,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Check that the state machine is updated accordingly
|
// Check that the state machine is updated accordingly
|
||||||
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
||||||
|
@ -1917,7 +1925,7 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Check that the state machine is updated accordingly
|
// Check that the state machine is updated accordingly
|
||||||
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
||||||
|
@ -2020,7 +2028,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Check that the state machine is updated accordingly
|
// Check that the state machine is updated accordingly
|
||||||
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
||||||
|
@ -2121,7 +2129,7 @@ func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Check that the state machine is updated accordingly
|
// Check that the state machine is updated accordingly
|
||||||
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
assertAddedToRouterGraph(t, alice, bob, fundingOutPoint)
|
||||||
|
@ -2192,7 +2200,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// The funding transaction is now confirmed, wait for the
|
// The funding transaction is now confirmed, wait for the
|
||||||
// OpenStatusUpdate_ChanOpen update
|
// OpenStatusUpdate_ChanOpen update
|
||||||
|
@ -2305,7 +2313,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) {
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements.
|
// announcements.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity)
|
assertChannelAnnouncements(t, alice, bob, capacity, nil, nil)
|
||||||
|
|
||||||
// Note: We don't check for the addedToRouterGraph state because in
|
// Note: We don't check for the addedToRouterGraph state because in
|
||||||
// the private channel mode, the state is quickly changed from
|
// the private channel mode, the state is quickly changed from
|
||||||
|
@ -2400,6 +2408,8 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
// This is the custom parameters we'll use.
|
// This is the custom parameters we'll use.
|
||||||
const csvDelay = 67
|
const csvDelay = 67
|
||||||
const minHtlcIn = 1234
|
const minHtlcIn = 1234
|
||||||
|
const maxValueInFlight = 50000
|
||||||
|
const fundingAmt = 5000000
|
||||||
|
|
||||||
// We will consume the channel updates as we go, so no buffering is
|
// We will consume the channel updates as we go, so no buffering is
|
||||||
// needed.
|
// needed.
|
||||||
|
@ -2413,15 +2423,16 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
// workflow.
|
// workflow.
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
initReq := &openChanReq{
|
initReq := &openChanReq{
|
||||||
targetPubkey: bob.privKey.PubKey(),
|
targetPubkey: bob.privKey.PubKey(),
|
||||||
chainHash: *activeNetParams.GenesisHash,
|
chainHash: *activeNetParams.GenesisHash,
|
||||||
localFundingAmt: localAmt,
|
localFundingAmt: localAmt,
|
||||||
pushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
|
pushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
|
||||||
private: false,
|
private: false,
|
||||||
minHtlcIn: minHtlcIn,
|
maxValueInFlight: maxValueInFlight,
|
||||||
remoteCsvDelay: csvDelay,
|
minHtlcIn: minHtlcIn,
|
||||||
updates: updateChan,
|
remoteCsvDelay: csvDelay,
|
||||||
err: errChan,
|
updates: updateChan,
|
||||||
|
err: errChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
alice.fundingMgr.initFundingWorkflow(bob, initReq)
|
alice.fundingMgr.initFundingWorkflow(bob, initReq)
|
||||||
|
@ -2460,6 +2471,12 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
minHtlcIn, openChannelReq.HtlcMinimum)
|
minHtlcIn, openChannelReq.HtlcMinimum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the max value in flight is sent as part of OpenChannel.
|
||||||
|
if openChannelReq.MaxValueInFlight != maxValueInFlight {
|
||||||
|
t.Fatalf("expected OpenChannel to have MaxValueInFlight %v, got %v",
|
||||||
|
maxValueInFlight, openChannelReq.MaxValueInFlight)
|
||||||
|
}
|
||||||
|
|
||||||
chanID := openChannelReq.PendingChannelID
|
chanID := openChannelReq.PendingChannelID
|
||||||
|
|
||||||
// Let Bob handle the init message.
|
// Let Bob handle the init message.
|
||||||
|
@ -2482,6 +2499,14 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
5, acceptChannelResponse.HtlcMinimum)
|
5, acceptChannelResponse.HtlcMinimum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reserve := lnwire.NewMSatFromSatoshis(fundingAmt / 100)
|
||||||
|
maxValueAcceptChannel := lnwire.NewMSatFromSatoshis(fundingAmt) - reserve
|
||||||
|
|
||||||
|
if acceptChannelResponse.MaxValueInFlight != maxValueAcceptChannel {
|
||||||
|
t.Fatalf("expected AcceptChannel to have MaxValueInFlight %v, got %v",
|
||||||
|
maxValueAcceptChannel, acceptChannelResponse.MaxValueInFlight)
|
||||||
|
}
|
||||||
|
|
||||||
// Forward the response to Alice.
|
// Forward the response to Alice.
|
||||||
alice.fundingMgr.processFundingAccept(acceptChannelResponse, bob)
|
alice.fundingMgr.processFundingAccept(acceptChannelResponse, bob)
|
||||||
|
|
||||||
|
@ -2527,6 +2552,27 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper method for checking the MaxValueInFlight stored for a
|
||||||
|
// reservation.
|
||||||
|
assertMaxHtlc := func(resCtx *reservationWithCtx,
|
||||||
|
expOurMaxValue, expTheirMaxValue lnwire.MilliSatoshi) error {
|
||||||
|
|
||||||
|
ourMaxValue :=
|
||||||
|
resCtx.reservation.OurContribution().MaxPendingAmount
|
||||||
|
if ourMaxValue != expOurMaxValue {
|
||||||
|
return fmt.Errorf("expected our maxValue to be %v, "+
|
||||||
|
"was %v", expOurMaxValue, ourMaxValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
theirMaxValue :=
|
||||||
|
resCtx.reservation.TheirContribution().MaxPendingAmount
|
||||||
|
if theirMaxValue != expTheirMaxValue {
|
||||||
|
return fmt.Errorf("expected their MaxPendingAmount to be %v, "+
|
||||||
|
"was %v", expTheirMaxValue, theirMaxValue)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the custom channel parameters were properly set in the
|
// Check that the custom channel parameters were properly set in the
|
||||||
// channel reservation.
|
// channel reservation.
|
||||||
resCtx, err := alice.fundingMgr.getReservationCtx(bobPubKey, chanID)
|
resCtx, err := alice.fundingMgr.getReservationCtx(bobPubKey, chanID)
|
||||||
|
@ -2534,7 +2580,7 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
t.Fatalf("unable to find ctx: %v", err)
|
t.Fatalf("unable to find ctx: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alice's CSV delay should be 4 since Bob sent the fedault value, and
|
// Alice's CSV delay should be 4 since Bob sent the default value, and
|
||||||
// Bob's should be 67 since Alice sent the custom value.
|
// Bob's should be 67 since Alice sent the custom value.
|
||||||
if err := assertDelay(resCtx, 4, csvDelay); err != nil {
|
if err := assertDelay(resCtx, 4, csvDelay); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -2546,6 +2592,14 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The max value in flight Alice can have should be maxValueAcceptChannel,
|
||||||
|
// which is the default value and the maxium Bob can offer should be
|
||||||
|
// maxValueInFlight.
|
||||||
|
if err := assertMaxHtlc(resCtx,
|
||||||
|
maxValueAcceptChannel, maxValueInFlight); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Also make sure the parameters are properly set on Bob's end.
|
// Also make sure the parameters are properly set on Bob's end.
|
||||||
resCtx, err = bob.fundingMgr.getReservationCtx(alicePubKey, chanID)
|
resCtx, err = bob.fundingMgr.getReservationCtx(alicePubKey, chanID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2560,6 +2614,10 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := assertMaxHtlc(resCtx,
|
||||||
|
maxValueInFlight, maxValueAcceptChannel); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
// Give the message to Bob.
|
// Give the message to Bob.
|
||||||
bob.fundingMgr.processFundingCreated(fundingCreated, alice)
|
bob.fundingMgr.processFundingCreated(fundingCreated, alice)
|
||||||
|
|
||||||
|
@ -2614,10 +2672,18 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
|
||||||
).(*lnwire.FundingLocked)
|
).(*lnwire.FundingLocked)
|
||||||
|
|
||||||
// Make sure both fundingManagers send the expected channel
|
// Make sure both fundingManagers send the expected channel
|
||||||
// announcements. Alice should advertise the default MinHTLC value of
|
// announcements.
|
||||||
|
// Alice should advertise the default MinHTLC value of
|
||||||
// 5, while bob should advertise the value minHtlc, since Alice
|
// 5, while bob should advertise the value minHtlc, since Alice
|
||||||
// required him to use it.
|
// required him to use it.
|
||||||
assertChannelAnnouncements(t, alice, bob, capacity, 5, minHtlcIn)
|
minHtlcArr := []lnwire.MilliSatoshi{5, minHtlcIn}
|
||||||
|
|
||||||
|
// For maxHltc Alice should advertise the default MaxHtlc value of
|
||||||
|
// maxValueAcceptChannel, while bob should advertise the value
|
||||||
|
// maxValueInFlight since Alice required him to use it.
|
||||||
|
maxHtlcArr := []lnwire.MilliSatoshi{maxValueAcceptChannel, maxValueInFlight}
|
||||||
|
|
||||||
|
assertChannelAnnouncements(t, alice, bob, capacity, minHtlcArr, maxHtlcArr)
|
||||||
|
|
||||||
// The funding transaction is now confirmed, wait for the
|
// The funding transaction is now confirmed, wait for the
|
||||||
// OpenStatusUpdate_ChanOpen update
|
// OpenStatusUpdate_ChanOpen update
|
||||||
|
|
1449
lnrpc/rpc.pb.go
1449
lnrpc/rpc.pb.go
File diff suppressed because it is too large
Load diff
|
@ -1593,6 +1593,12 @@ message OpenChannelRequest {
|
||||||
carried out in an interactive manner (PSBT based).
|
carried out in an interactive manner (PSBT based).
|
||||||
*/
|
*/
|
||||||
FundingShim funding_shim = 14;
|
FundingShim funding_shim = 14;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The maximum amount of coins in millisatoshi that can be pending within
|
||||||
|
the channel. It only applies to the remote party.
|
||||||
|
*/
|
||||||
|
uint64 remote_max_value_in_flight_msat = 15;
|
||||||
}
|
}
|
||||||
message OpenStatusUpdate {
|
message OpenStatusUpdate {
|
||||||
oneof update {
|
oneof update {
|
||||||
|
|
|
@ -4399,6 +4399,11 @@
|
||||||
"funding_shim": {
|
"funding_shim": {
|
||||||
"$ref": "#/definitions/lnrpcFundingShim",
|
"$ref": "#/definitions/lnrpcFundingShim",
|
||||||
"description": "Funding shims are an optional argument that allow the caller to intercept\ncertain funding functionality. For example, a shim can be provided to use a\nparticular key for the commitment key (ideally cold) rather than use one\nthat is generated by the wallet as normal, or signal that signing will be\ncarried out in an interactive manner (PSBT based)."
|
"description": "Funding shims are an optional argument that allow the caller to intercept\ncertain funding functionality. For example, a shim can be provided to use a\nparticular key for the commitment key (ideally cold) rather than use one\nthat is generated by the wallet as normal, or signal that signing will be\ncarried out in an interactive manner (PSBT based)."
|
||||||
|
},
|
||||||
|
"remote_max_value_in_flight_msat": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "The maximum amount of coins in millisatoshi that can be pending within\nthe channel. It only applies to the remote party."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
1
pilot.go
1
pilot.go
|
@ -106,6 +106,7 @@ func (c *chanController) OpenChannel(target *btcec.PublicKey,
|
||||||
private: c.private,
|
private: c.private,
|
||||||
remoteCsvDelay: 0,
|
remoteCsvDelay: 0,
|
||||||
minConfs: c.minConfs,
|
minConfs: c.minConfs,
|
||||||
|
maxValueInFlight: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStream, errChan := c.server.OpenChannel(req)
|
updateStream, errChan := c.server.OpenChannel(req)
|
||||||
|
|
22
rpcserver.go
22
rpcserver.go
|
@ -1711,6 +1711,7 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
||||||
remoteInitialBalance := btcutil.Amount(in.PushSat)
|
remoteInitialBalance := btcutil.Amount(in.PushSat)
|
||||||
minHtlcIn := lnwire.MilliSatoshi(in.MinHtlcMsat)
|
minHtlcIn := lnwire.MilliSatoshi(in.MinHtlcMsat)
|
||||||
remoteCsvDelay := uint16(in.RemoteCsvDelay)
|
remoteCsvDelay := uint16(in.RemoteCsvDelay)
|
||||||
|
maxValue := lnwire.MilliSatoshi(in.RemoteMaxValueInFlightMsat)
|
||||||
|
|
||||||
// Ensure that the initial balance of the remote party (if pushing
|
// Ensure that the initial balance of the remote party (if pushing
|
||||||
// satoshis) does not exceed the amount the local party has requested
|
// satoshis) does not exceed the amount the local party has requested
|
||||||
|
@ -1813,16 +1814,17 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
||||||
// open a new channel. A stream is returned in place, this stream will
|
// 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.
|
// be used to consume updates of the state of the pending channel.
|
||||||
return &openChanReq{
|
return &openChanReq{
|
||||||
targetPubkey: nodePubKey,
|
targetPubkey: nodePubKey,
|
||||||
chainHash: *activeNetParams.GenesisHash,
|
chainHash: *activeNetParams.GenesisHash,
|
||||||
localFundingAmt: localFundingAmt,
|
localFundingAmt: localFundingAmt,
|
||||||
pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance),
|
pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance),
|
||||||
minHtlcIn: minHtlcIn,
|
minHtlcIn: minHtlcIn,
|
||||||
fundingFeePerKw: feeRate,
|
fundingFeePerKw: feeRate,
|
||||||
private: in.Private,
|
private: in.Private,
|
||||||
remoteCsvDelay: remoteCsvDelay,
|
remoteCsvDelay: remoteCsvDelay,
|
||||||
minConfs: minConfs,
|
minConfs: minConfs,
|
||||||
shutdownScript: script,
|
shutdownScript: script,
|
||||||
|
maxValueInFlight: maxValue,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3262,6 +3262,10 @@ type openChanReq struct {
|
||||||
// This value is optional, so may be nil.
|
// This value is optional, so may be nil.
|
||||||
shutdownScript lnwire.DeliveryAddress
|
shutdownScript lnwire.DeliveryAddress
|
||||||
|
|
||||||
|
// maxValueInFlight is the maximum amount of coins in millisatoshi that can
|
||||||
|
// be pending within the channel. It only applies to the remote party.
|
||||||
|
maxValueInFlight lnwire.MilliSatoshi
|
||||||
|
|
||||||
// TODO(roasbeef): add ability to specify channel constraints as well
|
// TODO(roasbeef): add ability to specify channel constraints as well
|
||||||
|
|
||||||
// chanFunder is an optional channel funder that allows the caller to
|
// chanFunder is an optional channel funder that allows the caller to
|
||||||
|
|
Loading…
Add table
Reference in a new issue