lnwallet: add noop HTLC tests
Adds some simple tests to check the noop HTLC logic of the lightning channel.
This commit is contained in:
1 file changed
+140
@@ -11339,3 +11339,143 @@ func TestCreateCooperativeCloseTx(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNoopAddSettle tests that adding and settling an HTLC with no-op, no
|
||||
// balances are actually affected.
|
||||
func TestNoopAddSettle(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a test channel which will be used for the duration of this
|
||||
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
||||
// and Bob having 5 BTC.
|
||||
chanType := channeldb.SimpleTaprootFeatureBit |
|
||||
channeldb.AnchorOutputsBit | channeldb.ZeroHtlcTxFeeBit |
|
||||
channeldb.SingleFunderTweaklessBit | channeldb.TapscriptRootBit
|
||||
aliceChannel, bobChannel, err := CreateTestChannels(
|
||||
t, chanType,
|
||||
)
|
||||
require.NoError(t, err, "unable to create test channels")
|
||||
|
||||
const htlcAmt = 10_000
|
||||
htlc, preimage := createHTLC(0, htlcAmt)
|
||||
noopRecord := tlv.NewPrimitiveRecord[tlv.TlvType65544, bool](true)
|
||||
|
||||
records, err := tlv.RecordsToMap([]tlv.Record{noopRecord.Record()})
|
||||
require.NoError(t, err)
|
||||
htlc.CustomRecords = records
|
||||
|
||||
aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance
|
||||
bobBalance := bobChannel.channelState.LocalCommitment.LocalBalance
|
||||
|
||||
// Have Alice add the HTLC, then lock it in with a new state transition.
|
||||
aliceHtlcIndex, err := aliceChannel.AddHTLC(htlc, nil)
|
||||
require.NoError(t, err, "alice unable to add htlc")
|
||||
bobHtlcIndex, err := bobChannel.ReceiveHTLC(htlc)
|
||||
require.NoError(t, err, "bob unable to receive htlc")
|
||||
|
||||
err = ForceStateTransition(aliceChannel, bobChannel)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We'll have Bob settle the HTLC, then force another state transition.
|
||||
err = bobChannel.SettleHTLC(preimage, bobHtlcIndex, nil, nil, nil)
|
||||
require.NoError(t, err, "bob unable to settle inbound htlc")
|
||||
err = aliceChannel.ReceiveHTLCSettle(preimage, aliceHtlcIndex)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ForceStateTransition(aliceChannel, bobChannel)
|
||||
require.NoError(t, err)
|
||||
|
||||
aliceBalanceFinal := aliceChannel.channelState.LocalCommitment.LocalBalance //nolint:ll
|
||||
bobBalanceFinal := bobChannel.channelState.LocalCommitment.LocalBalance
|
||||
|
||||
// The balances of Alice and Bob should be the exact same and shouldn't
|
||||
// have changed.
|
||||
require.Equal(t, aliceBalance, aliceBalanceFinal)
|
||||
require.Equal(t, bobBalance, bobBalanceFinal)
|
||||
}
|
||||
|
||||
// TestNoopAddBelowReserve tests that the noop HTLCs behave as expected when
|
||||
// added over a channel where a party is below their reserve.
|
||||
func TestNoopAddBelowReserve(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a test channel which will be used for the duration of this
|
||||
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
||||
// and Bob having 5 BTC.
|
||||
chanType := channeldb.SimpleTaprootFeatureBit |
|
||||
channeldb.AnchorOutputsBit | channeldb.ZeroHtlcTxFeeBit |
|
||||
channeldb.SingleFunderTweaklessBit | channeldb.TapscriptRootBit
|
||||
aliceChan, bobChan, err := CreateTestChannels(t, chanType)
|
||||
require.NoError(t, err, "unable to create test channels")
|
||||
|
||||
aliceBalance := aliceChan.channelState.LocalCommitment.LocalBalance
|
||||
bobBalance := bobChan.channelState.LocalCommitment.LocalBalance
|
||||
|
||||
const (
|
||||
// htlcAmt is the default HTLC amount to be used, epxressed in
|
||||
// milli-satoshis.
|
||||
htlcAmt = lnwire.MilliSatoshi(500_000)
|
||||
|
||||
// numHtlc is the total number of HTLCs to be added/settled over
|
||||
// the channel.
|
||||
numHtlc = 20
|
||||
)
|
||||
|
||||
// Let's create the noop add TLV record to be used in all added HTLCs
|
||||
// over the channel.
|
||||
noopRecord := tlv.NewPrimitiveRecord[NoOpHtlcTLVType, bool](true)
|
||||
records, err := tlv.RecordsToMap([]tlv.Record{noopRecord.Record()})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Let's set Bob's reserve to whatever his local balance is, plus half
|
||||
// of the total amount to be added by the total HTLCs. This way we can
|
||||
// also verify that the noop-adds will start the nullification only once
|
||||
// Bob is above reserve.
|
||||
reserveTarget := (numHtlc / 2) * htlcAmt
|
||||
bobReserve := bobBalance + reserveTarget
|
||||
|
||||
bobChan.channelState.LocalChanCfg.ChanReserve =
|
||||
bobReserve.ToSatoshis()
|
||||
|
||||
aliceChan.channelState.RemoteChanCfg.ChanReserve =
|
||||
bobReserve.ToSatoshis()
|
||||
|
||||
// Add and settle all the HTLCs over the channel.
|
||||
for i := range numHtlc {
|
||||
htlc, preimage := createHTLC(i, htlcAmt)
|
||||
htlc.CustomRecords = records
|
||||
|
||||
aliceHtlcIndex, err := aliceChan.AddHTLC(htlc, nil)
|
||||
require.NoError(t, err, "alice unable to add htlc")
|
||||
bobHtlcIndex, err := bobChan.ReceiveHTLC(htlc)
|
||||
require.NoError(t, err, "bob unable to receive htlc")
|
||||
|
||||
require.NoError(t, ForceStateTransition(aliceChan, bobChan))
|
||||
|
||||
// We'll have Bob settle the HTLC, then force another state
|
||||
// transition.
|
||||
err = bobChan.SettleHTLC(preimage, bobHtlcIndex, nil, nil, nil)
|
||||
require.NoError(t, err, "bob unable to settle inbound htlc")
|
||||
err = aliceChan.ReceiveHTLCSettle(preimage, aliceHtlcIndex)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, ForceStateTransition(aliceChan, bobChan))
|
||||
}
|
||||
|
||||
// We need to kick the state transition one last time for the balances
|
||||
// to be updated on both commitments.
|
||||
require.NoError(t, ForceStateTransition(aliceChan, bobChan))
|
||||
|
||||
aliceBalanceFinal := aliceChan.channelState.LocalCommitment.LocalBalance
|
||||
bobBalanceFinal := bobChan.channelState.LocalCommitment.LocalBalance
|
||||
|
||||
// The balances of Alice and Bob must have changed exactly by half the
|
||||
// total number of HTLCs we added over the channel, plus one to get Bob
|
||||
// above the reserve. Bob's final balance should be as much as his
|
||||
// reserve plus one extra default HTLC amount.
|
||||
require.Equal(t, aliceBalance-htlcAmt*(numHtlc/2+1), aliceBalanceFinal)
|
||||
require.Equal(t, bobBalance+htlcAmt*(numHtlc/2+1), bobBalanceFinal)
|
||||
require.Equal(
|
||||
t, bobBalanceFinal.ToSatoshis(),
|
||||
bobChan.LocalChanReserve()+htlcAmt.ToSatoshis(),
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user