mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 09:48:19 +01:00
htlcswitch test: add TestChannelLinkBandwidthChanReserve
This commit is contained in:
parent
e6f7a46d90
commit
509adce2ad
2 changed files with 144 additions and 12 deletions
|
@ -1405,8 +1405,8 @@ func (m *mockPeer) Disconnect(reason error) {
|
||||||
|
|
||||||
var _ Peer = (*mockPeer)(nil)
|
var _ Peer = (*mockPeer)(nil)
|
||||||
|
|
||||||
func newSingleLinkTestHarness(chanAmt btcutil.Amount) (ChannelLink,
|
func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
|
||||||
*lnwallet.LightningChannel, chan time.Time, func(), error) {
|
ChannelLink, *lnwallet.LightningChannel, chan time.Time, func(), error) {
|
||||||
globalEpoch := &chainntnfs.BlockEpochEvent{
|
globalEpoch := &chainntnfs.BlockEpochEvent{
|
||||||
Epochs: make(chan *chainntnfs.BlockEpoch),
|
Epochs: make(chan *chainntnfs.BlockEpoch),
|
||||||
Cancel: func() {
|
Cancel: func() {
|
||||||
|
@ -1415,7 +1415,8 @@ func newSingleLinkTestHarness(chanAmt btcutil.Amount) (ChannelLink,
|
||||||
|
|
||||||
chanID := lnwire.NewShortChanIDFromInt(4)
|
chanID := lnwire.NewShortChanIDFromInt(4)
|
||||||
aliceChannel, bobChannel, fCleanUp, _, err := createTestChannel(
|
aliceChannel, bobChannel, fCleanUp, _, err := createTestChannel(
|
||||||
alicePrivKey, bobPrivKey, chanAmt, chanAmt, chanID,
|
alicePrivKey, bobPrivKey, chanAmt, chanAmt,
|
||||||
|
chanReserve, chanReserve, chanID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
|
@ -1659,7 +1660,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
|
||||||
|
|
||||||
// We'll start the test by creating a single instance of
|
// We'll start the test by creating a single instance of
|
||||||
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
||||||
link, bobChannel, tmr, cleanUp, err := newSingleLinkTestHarness(chanAmt)
|
link, bobChannel, tmr, cleanUp, err := newSingleLinkTestHarness(chanAmt, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create link: %v", err)
|
t.Fatalf("unable to create link: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1992,7 +1993,8 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
|
||||||
var mockBlob [lnwire.OnionPacketSize]byte
|
var mockBlob [lnwire.OnionPacketSize]byte
|
||||||
|
|
||||||
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
||||||
aliceLink, bobChannel, batchTick, cleanUp, err := newSingleLinkTestHarness(chanAmt)
|
aliceLink, bobChannel, batchTick, cleanUp, err :=
|
||||||
|
newSingleLinkTestHarness(chanAmt, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create link: %v", err)
|
t.Fatalf("unable to create link: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -2191,6 +2193,134 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestChannelLinkBandwidthChanReserve checks that the bandwidth available
|
||||||
|
// on the channel link reflects the channel reserve that must be kept
|
||||||
|
// at all times.
|
||||||
|
func TestChannelLinkBandwidthChanReserve(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// First start a link that has a balance greater than it's
|
||||||
|
// channel reserve.
|
||||||
|
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
||||||
|
const chanReserve = btcutil.SatoshiPerBitcoin * 1
|
||||||
|
aliceLink, bobChannel, batchTimer, cleanUp, err :=
|
||||||
|
newSingleLinkTestHarness(chanAmt, chanReserve)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create link: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanUp()
|
||||||
|
|
||||||
|
var (
|
||||||
|
mockBlob [lnwire.OnionPacketSize]byte
|
||||||
|
coreLink = aliceLink.(*channelLink)
|
||||||
|
coreChan = coreLink.channel
|
||||||
|
defaultCommitFee = coreChan.StateSnapshot().CommitFee
|
||||||
|
aliceStartingBandwidth = aliceLink.Bandwidth()
|
||||||
|
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
||||||
|
)
|
||||||
|
|
||||||
|
estimator := &lnwallet.StaticFeeEstimator{
|
||||||
|
FeeRate: 24,
|
||||||
|
}
|
||||||
|
feePerWeight, err := estimator.EstimateFeePerWeight(1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
|
}
|
||||||
|
feePerKw := feePerWeight * 1000
|
||||||
|
htlcFee := lnwire.NewMSatFromSatoshis(
|
||||||
|
btcutil.Amount((int64(feePerKw) * lnwallet.HtlcWeight) / 1000),
|
||||||
|
)
|
||||||
|
|
||||||
|
// The starting bandwidth of the channel should be exactly the amount
|
||||||
|
// that we created the channel between her and Bob, minus the channel
|
||||||
|
// reserve.
|
||||||
|
expectedBandwidth := lnwire.NewMSatFromSatoshis(
|
||||||
|
chanAmt - defaultCommitFee - chanReserve)
|
||||||
|
assertLinkBandwidth(t, aliceLink, expectedBandwidth)
|
||||||
|
|
||||||
|
// Next, we'll create an HTLC worth 3 BTC, and send it into the link as
|
||||||
|
// a switch initiated payment. The resulting bandwidth should
|
||||||
|
// now be decremented to reflect the new HTLC.
|
||||||
|
htlcAmt := lnwire.NewMSatFromSatoshis(3 * btcutil.SatoshiPerBitcoin)
|
||||||
|
invoice, htlc, err := generatePayment(htlcAmt, htlcAmt, 5, mockBlob)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create payment: %v", err)
|
||||||
|
}
|
||||||
|
addPkt := htlcPacket{
|
||||||
|
htlc: htlc,
|
||||||
|
}
|
||||||
|
aliceLink.HandleSwitchPacket(&addPkt)
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
|
||||||
|
|
||||||
|
// Alice should send the HTLC to Bob.
|
||||||
|
var msg lnwire.Message
|
||||||
|
select {
|
||||||
|
case msg = <-aliceMsgs:
|
||||||
|
case <-time.After(2 * time.Second):
|
||||||
|
t.Fatalf("did not receive message")
|
||||||
|
}
|
||||||
|
|
||||||
|
addHtlc, ok := msg.(*lnwire.UpdateAddHTLC)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected UpdateAddHTLC, got %T", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobIndex, err := bobChannel.ReceiveHTLC(addHtlc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob failed receiving htlc: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock in the HTLC.
|
||||||
|
if err := updateState(batchTimer, coreLink, bobChannel, true); err != nil {
|
||||||
|
t.Fatalf("unable to update state: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
|
||||||
|
|
||||||
|
// If we now send in a valid HTLC settle for the prior HTLC we added,
|
||||||
|
// then the bandwidth should remain unchanged as the remote party will
|
||||||
|
// gain additional channel balance.
|
||||||
|
err = bobChannel.SettleHTLC(invoice.Terms.PaymentPreimage, bobIndex)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to settle htlc: %v", err)
|
||||||
|
}
|
||||||
|
htlcSettle := &lnwire.UpdateFulfillHTLC{
|
||||||
|
ID: bobIndex,
|
||||||
|
PaymentPreimage: invoice.Terms.PaymentPreimage,
|
||||||
|
}
|
||||||
|
aliceLink.HandleChannelUpdate(htlcSettle)
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
|
||||||
|
// Since the settle is not locked in yet, Alice's bandwidth should still
|
||||||
|
// reflect that she has to pay the fee.
|
||||||
|
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
|
||||||
|
|
||||||
|
// Lock in the settle.
|
||||||
|
if err := updateState(batchTimer, coreLink, bobChannel, false); err != nil {
|
||||||
|
t.Fatalf("unable to update state: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt)
|
||||||
|
|
||||||
|
// Now we create a channel that has a channel reserve that is
|
||||||
|
// greater than it's balance. In these case only payments can
|
||||||
|
// be received on this channel, not sent. The available bandwidth
|
||||||
|
// should therefore be 0.
|
||||||
|
const bobChanAmt = btcutil.SatoshiPerBitcoin * 1
|
||||||
|
const bobChanReserve = btcutil.SatoshiPerBitcoin * 1.5
|
||||||
|
bobLink, _, _, bobCleanUp, err := newSingleLinkTestHarness(bobChanAmt,
|
||||||
|
bobChanReserve)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create link: %v", err)
|
||||||
|
}
|
||||||
|
defer bobCleanUp()
|
||||||
|
|
||||||
|
// Make sure bandwidth is reported as 0.
|
||||||
|
assertLinkBandwidth(t, bobLink, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// TestChannelRetransmission tests the ability of the channel links to
|
// TestChannelRetransmission tests the ability of the channel links to
|
||||||
// synchronize theirs states after abrupt disconnect.
|
// synchronize theirs states after abrupt disconnect.
|
||||||
func TestChannelRetransmission(t *testing.T) {
|
func TestChannelRetransmission(t *testing.T) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ func generateRandomBytes(n int) ([]byte, error) {
|
||||||
//
|
//
|
||||||
// TODO(roasbeef): need to factor out, similar func re-used in many parts of codebase
|
// TODO(roasbeef): need to factor out, similar func re-used in many parts of codebase
|
||||||
func createTestChannel(alicePrivKey, bobPrivKey []byte,
|
func createTestChannel(alicePrivKey, bobPrivKey []byte,
|
||||||
aliceAmount, bobAmount btcutil.Amount,
|
aliceAmount, bobAmount, aliceReserve, bobReserve btcutil.Amount,
|
||||||
chanID lnwire.ShortChannelID) (*lnwallet.LightningChannel, *lnwallet.LightningChannel, func(),
|
chanID lnwire.ShortChannelID) (*lnwallet.LightningChannel, *lnwallet.LightningChannel, func(),
|
||||||
func() (*lnwallet.LightningChannel, *lnwallet.LightningChannel,
|
func() (*lnwallet.LightningChannel, *lnwallet.LightningChannel,
|
||||||
error), error) {
|
error), error) {
|
||||||
|
@ -104,7 +104,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
|
||||||
DustLimit: btcutil.Amount(200),
|
DustLimit: btcutil.Amount(200),
|
||||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(
|
MaxPendingAmount: lnwire.NewMSatFromSatoshis(
|
||||||
channelCapacity),
|
channelCapacity),
|
||||||
ChanReserve: 0,
|
ChanReserve: aliceReserve,
|
||||||
MinHTLC: 0,
|
MinHTLC: 0,
|
||||||
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
|
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
|
||||||
DustLimit: btcutil.Amount(800),
|
DustLimit: btcutil.Amount(800),
|
||||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(
|
MaxPendingAmount: lnwire.NewMSatFromSatoshis(
|
||||||
channelCapacity),
|
channelCapacity),
|
||||||
ChanReserve: 0,
|
ChanReserve: bobReserve,
|
||||||
MinHTLC: 0,
|
MinHTLC: 0,
|
||||||
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
|
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
|
||||||
}
|
}
|
||||||
|
@ -668,15 +668,17 @@ func createClusterChannels(aliceToBob, bobToCarol btcutil.Amount) (
|
||||||
secondChanID := lnwire.NewShortChanIDFromInt(5)
|
secondChanID := lnwire.NewShortChanIDFromInt(5)
|
||||||
|
|
||||||
// Create lightning channels between Alice<->Bob and Bob<->Carol
|
// Create lightning channels between Alice<->Bob and Bob<->Carol
|
||||||
aliceChannel, firstBobChannel, cleanAliceBob, restoreAliceBob, err := createTestChannel(
|
aliceChannel, firstBobChannel, cleanAliceBob, restoreAliceBob, err :=
|
||||||
alicePrivKey, bobPrivKey, aliceToBob, aliceToBob, firstChanID)
|
createTestChannel(alicePrivKey, bobPrivKey, aliceToBob,
|
||||||
|
aliceToBob, 0, 0, firstChanID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, errors.Errorf("unable to create "+
|
return nil, nil, nil, errors.Errorf("unable to create "+
|
||||||
"alice<->bob channel: %v", err)
|
"alice<->bob channel: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
secondBobChannel, carolChannel, cleanBobCarol, restoreBobCarol, err := createTestChannel(
|
secondBobChannel, carolChannel, cleanBobCarol, restoreBobCarol, err :=
|
||||||
bobPrivKey, carolPrivKey, bobToCarol, bobToCarol, secondChanID)
|
createTestChannel(bobPrivKey, carolPrivKey, bobToCarol,
|
||||||
|
bobToCarol, 0, 0, secondChanID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanAliceBob()
|
cleanAliceBob()
|
||||||
return nil, nil, nil, errors.Errorf("unable to create "+
|
return nil, nil, nil, errors.Errorf("unable to create "+
|
||||||
|
|
Loading…
Add table
Reference in a new issue