Skip to content

Commit e42780b

Browse files
committed
lnwallet: add comprehensive tests for LocalNonces sync
Adds extensive test coverage for the new LocalNonces functionality in channel synchronization, ensuring both legacy and new nonce fields work correctly together. Test additions include: - Helper function to extract nonces from either LocalNonces or LocalNonce - Comprehensive TestChanSyncTaprootLocalNonces covering all scenarios - Tests for backwards compatibility when only one field is present - Error handling tests for missing nonce scenarios - Updates to existing sync tests to handle both nonce field types
1 parent 62de9bc commit e42780b

File tree

1 file changed

+88
-3
lines changed

1 file changed

+88
-3
lines changed

lnwallet/channel_test.go

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,6 +3073,25 @@ func TestAddHTLCNegativeBalance(t *testing.T) {
30733073
// assertNoChanSyncNeeded is a helper function that asserts that upon restart,
30743074
// two channels conclude that they're fully synchronized and don't need to
30753075
// retransmit any new messages.
3076+
// extractCommitmentNonce extracts the commitment nonce from a ChannelReestablish
3077+
// message, prioritizing LocalNonces over the legacy LocalNonce field.
3078+
func extractCommitmentNonce(t *testing.T, msg *lnwire.ChannelReestablish) lnwire.Musig2Nonce {
3079+
// Prefer LocalNonces if present
3080+
if msg.LocalNonces.IsSome() {
3081+
noncesData := msg.LocalNonces.UnwrapOrFail(t)
3082+
3083+
// Return the first nonce (for main commitment)
3084+
for _, nonce := range noncesData.NoncesMap {
3085+
return nonce
3086+
}
3087+
3088+
// If map is empty, fall back to LocalNonce
3089+
}
3090+
3091+
// Fall back to legacy LocalNonce field
3092+
return msg.LocalNonce.UnwrapOrFailV(t)
3093+
}
3094+
30763095
func assertNoChanSyncNeeded(t *testing.T, aliceChannel *LightningChannel,
30773096
bobChannel *LightningChannel) {
30783097

@@ -3090,13 +3109,14 @@ func assertNoChanSyncNeeded(t *testing.T, aliceChannel *LightningChannel,
30903109
}
30913110

30923111
// For taproot channels, simulate the link/peer binding the generated
3093-
// nonces.
3112+
// nonces. Use helper to extract nonces from either LocalNonces or
3113+
// LocalNonce.
30943114
if aliceChannel.channelState.ChanType.IsTaproot() {
30953115
aliceChannel.pendingVerificationNonce = &musig2.Nonces{
3096-
PubNonce: aliceChanSyncMsg.LocalNonce.UnwrapOrFailV(t),
3116+
PubNonce: extractCommitmentNonce(t, aliceChanSyncMsg),
30973117
}
30983118
bobChannel.pendingVerificationNonce = &musig2.Nonces{
3099-
PubNonce: bobChanSyncMsg.LocalNonce.UnwrapOrFailV(t),
3119+
PubNonce: extractCommitmentNonce(t, bobChanSyncMsg),
31003120
}
31013121
}
31023122

@@ -3538,6 +3558,71 @@ func testChanSyncOweCommitment(t *testing.T, chanType channeldb.ChannelType) {
35383558
}
35393559
}
35403560

3561+
// TestChanSyncTaprootLocalNonces tests that for taproot channels, both the
3562+
// legacy LocalNonce field and the new LocalNonces field are populated in
3563+
// ChannelReestablish messages, and that the receiving side can handle either.
3564+
func TestChanSyncTaprootLocalNonces(t *testing.T) {
3565+
t.Parallel()
3566+
3567+
// Create a taproot test channel.
3568+
chanType := channeldb.SimpleTaprootFeatureBit
3569+
aliceChannel, bobChannel, err := CreateTestChannels(t, chanType)
3570+
require.NoError(t, err, "unable to create test channels")
3571+
3572+
// Both sides should be fully synced from the start.
3573+
assertNoChanSyncNeeded(t, aliceChannel, bobChannel)
3574+
3575+
// Generate ChannelReestablish messages.
3576+
aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg()
3577+
require.NoError(t, err, "unable to produce chan sync msg")
3578+
bobChanSyncMsg, err := bobChannel.channelState.ChanSyncMsg()
3579+
require.NoError(t, err, "unable to produce chan sync msg")
3580+
3581+
// For taproot channels, both LocalNonce and LocalNonces should be populated.
3582+
require.True(t, aliceChanSyncMsg.LocalNonce.IsSome(), "LocalNonce should be set")
3583+
require.True(t, aliceChanSyncMsg.LocalNonces.IsSome(), "LocalNonces should be set")
3584+
require.True(t, bobChanSyncMsg.LocalNonce.IsSome(), "LocalNonce should be set")
3585+
require.True(t, bobChanSyncMsg.LocalNonces.IsSome(), "LocalNonces should be set")
3586+
3587+
// The nonces from both fields should be identical.
3588+
aliceLegacyNonce := aliceChanSyncMsg.LocalNonce.UnwrapOrFailV(t)
3589+
aliceNoncesData := aliceChanSyncMsg.LocalNonces.UnwrapOrFail(t)
3590+
require.Len(t, aliceNoncesData.NoncesMap, 1, "should have exactly one nonce")
3591+
var aliceMapNonce lnwire.Musig2Nonce
3592+
for _, nonce := range aliceNoncesData.NoncesMap {
3593+
aliceMapNonce = nonce
3594+
break
3595+
}
3596+
require.Equal(t, aliceLegacyNonce, aliceMapNonce, "nonces should match")
3597+
3598+
// Test that our helper function works correctly.
3599+
extractedNonce := extractCommitmentNonce(t, aliceChanSyncMsg)
3600+
require.Equal(t, aliceLegacyNonce, extractedNonce, "helper should extract correct nonce")
3601+
3602+
// Test sync behavior when only LocalNonces is present by clearing LocalNonce.
3603+
aliceModifiedMsg := *aliceChanSyncMsg
3604+
aliceModifiedMsg.LocalNonce = lnwire.OptMusig2NonceTLV{}
3605+
3606+
// Bob should still be able to process the message with only LocalNonces.
3607+
bobChannel.pendingVerificationNonce = &musig2.Nonces{
3608+
PubNonce: extractCommitmentNonce(t, bobChanSyncMsg),
3609+
}
3610+
bobMsgsToSend, _, _, err := bobChannel.ProcessChanSyncMsg(
3611+
ctxb, &aliceModifiedMsg,
3612+
)
3613+
require.NoError(t, err, "unable to process modified ChannelReestablish msg")
3614+
require.Empty(t, bobMsgsToSend, "bob shouldn't need to send messages")
3615+
3616+
// Test that missing both fields results in an error.
3617+
aliceEmptyMsg := *aliceChanSyncMsg
3618+
aliceEmptyMsg.LocalNonce = lnwire.OptMusig2NonceTLV{}
3619+
aliceEmptyMsg.LocalNonces = lnwire.OptLocalNonces{}
3620+
3621+
_, _, _, err = bobChannel.ProcessChanSyncMsg(ctxb, &aliceEmptyMsg)
3622+
require.Error(t, err, "should error when no nonce is provided")
3623+
require.Contains(t, err.Error(), "remote verification nonce not sent")
3624+
}
3625+
35413626
// TestChanSyncOweCommitment tests that if Bob restarts (and then Alice) before
35423627
// he receives Alice's CommitSig message, then Alice concludes that she needs
35433628
// to re-send the CommitDiff. After the diff has been sent, both nodes should

0 commit comments

Comments
 (0)