htlcswitch test: add TestChannelLinkBandwidthChanReserve

This commit is contained in:
Johan T. Halseth 2018-02-07 19:45:19 -05:00
parent e6f7a46d90
commit 509adce2ad
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 144 additions and 12 deletions

@ -1405,8 +1405,8 @@ func (m *mockPeer) Disconnect(reason error) {
var _ Peer = (*mockPeer)(nil)
func newSingleLinkTestHarness(chanAmt btcutil.Amount) (ChannelLink,
*lnwallet.LightningChannel, chan time.Time, func(), error) {
func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
ChannelLink, *lnwallet.LightningChannel, chan time.Time, func(), error) {
globalEpoch := &chainntnfs.BlockEpochEvent{
Epochs: make(chan *chainntnfs.BlockEpoch),
Cancel: func() {
@ -1415,7 +1415,8 @@ func newSingleLinkTestHarness(chanAmt btcutil.Amount) (ChannelLink,
chanID := lnwire.NewShortChanIDFromInt(4)
aliceChannel, bobChannel, fCleanUp, _, err := createTestChannel(
alicePrivKey, bobPrivKey, chanAmt, chanAmt, chanID,
alicePrivKey, bobPrivKey, chanAmt, chanAmt,
chanReserve, chanReserve, chanID,
)
if err != nil {
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
const chanAmt = btcutil.SatoshiPerBitcoin * 5
link, bobChannel, tmr, cleanUp, err := newSingleLinkTestHarness(chanAmt)
link, bobChannel, tmr, cleanUp, err := newSingleLinkTestHarness(chanAmt, 0)
if err != nil {
t.Fatalf("unable to create link: %v", err)
}
@ -1992,7 +1993,8 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
var mockBlob [lnwire.OnionPacketSize]byte
const chanAmt = btcutil.SatoshiPerBitcoin * 5
aliceLink, bobChannel, batchTick, cleanUp, err := newSingleLinkTestHarness(chanAmt)
aliceLink, bobChannel, batchTick, cleanUp, err :=
newSingleLinkTestHarness(chanAmt, 0)
if err != nil {
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
// synchronize theirs states after abrupt disconnect.
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
func createTestChannel(alicePrivKey, bobPrivKey []byte,
aliceAmount, bobAmount btcutil.Amount,
aliceAmount, bobAmount, aliceReserve, bobReserve btcutil.Amount,
chanID lnwire.ShortChannelID) (*lnwallet.LightningChannel, *lnwallet.LightningChannel, func(),
func() (*lnwallet.LightningChannel, *lnwallet.LightningChannel,
error), error) {
@ -104,7 +104,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
DustLimit: btcutil.Amount(200),
MaxPendingAmount: lnwire.NewMSatFromSatoshis(
channelCapacity),
ChanReserve: 0,
ChanReserve: aliceReserve,
MinHTLC: 0,
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
}
@ -113,7 +113,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
DustLimit: btcutil.Amount(800),
MaxPendingAmount: lnwire.NewMSatFromSatoshis(
channelCapacity),
ChanReserve: 0,
ChanReserve: bobReserve,
MinHTLC: 0,
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
}
@ -668,15 +668,17 @@ func createClusterChannels(aliceToBob, bobToCarol btcutil.Amount) (
secondChanID := lnwire.NewShortChanIDFromInt(5)
// Create lightning channels between Alice<->Bob and Bob<->Carol
aliceChannel, firstBobChannel, cleanAliceBob, restoreAliceBob, err := createTestChannel(
alicePrivKey, bobPrivKey, aliceToBob, aliceToBob, firstChanID)
aliceChannel, firstBobChannel, cleanAliceBob, restoreAliceBob, err :=
createTestChannel(alicePrivKey, bobPrivKey, aliceToBob,
aliceToBob, 0, 0, firstChanID)
if err != nil {
return nil, nil, nil, errors.Errorf("unable to create "+
"alice<->bob channel: %v", err)
}
secondBobChannel, carolChannel, cleanBobCarol, restoreBobCarol, err := createTestChannel(
bobPrivKey, carolPrivKey, bobToCarol, bobToCarol, secondChanID)
secondBobChannel, carolChannel, cleanBobCarol, restoreBobCarol, err :=
createTestChannel(bobPrivKey, carolPrivKey, bobToCarol,
bobToCarol, 0, 0, secondChanID)
if err != nil {
cleanAliceBob()
return nil, nil, nil, errors.Errorf("unable to create "+