Skip to content

Commit 222f49c

Browse files
channeldb: add MarkConfirmationHeight to OpenChannel
Add the MarkConfirmationHeight method to the OpenChannel struct to record the block height at which the funding transaction was first confirmed. Also, introduce the ConfirmationHeight field to persist this information in the database. Signed-off-by: Nishant Bansal <[email protected]>
1 parent 7bc6331 commit 222f49c

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

channeldb/channel.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ type openChannelTlvData struct {
261261
// customBlob is an optional TLV encoded blob of data representing
262262
// custom channel funding information.
263263
customBlob tlv.OptionalRecordT[tlv.TlvType7, tlv.Blob]
264+
265+
// confirmationHeight records the block height at which the funding
266+
// transaction was first confirmed.
267+
confirmationHeight tlv.RecordT[tlv.TlvType8, uint32]
264268
}
265269

266270
// encode serializes the openChannelTlvData to the given io.Writer.
@@ -270,6 +274,7 @@ func (c *openChannelTlvData) encode(w io.Writer) error {
270274
c.initialLocalBalance.Record(),
271275
c.initialRemoteBalance.Record(),
272276
c.realScid.Record(),
277+
c.confirmationHeight.Record(),
273278
}
274279
c.memo.WhenSome(func(memo tlv.RecordT[tlv.TlvType5, []byte]) {
275280
tlvRecords = append(tlvRecords, memo.Record())
@@ -283,6 +288,8 @@ func (c *openChannelTlvData) encode(w io.Writer) error {
283288
tlvRecords = append(tlvRecords, blob.Record())
284289
})
285290

291+
tlv.SortRecords(tlvRecords)
292+
286293
// Create the tlv stream.
287294
tlvStream, err := tlv.NewStream(tlvRecords...)
288295
if err != nil {
@@ -307,6 +314,7 @@ func (c *openChannelTlvData) decode(r io.Reader) error {
307314
memo.Record(),
308315
tapscriptRoot.Record(),
309316
blob.Record(),
317+
c.confirmationHeight.Record(),
310318
)
311319
if err != nil {
312320
return err
@@ -906,6 +914,10 @@ type OpenChannel struct {
906914
// been confirmed before a certain height.
907915
FundingBroadcastHeight uint32
908916

917+
// ConfirmationHeight records the block height at which the funding
918+
// transaction was first confirmed.
919+
ConfirmationHeight uint32
920+
909921
// NumConfsRequired is the number of confirmations a channel's funding
910922
// transaction must have received in order to be considered available
911923
// for normal transactional use.
@@ -1207,6 +1219,7 @@ func (c *OpenChannel) amendTlvData(auxData openChannelTlvData) {
12071219
auxData.initialRemoteBalance.Val,
12081220
)
12091221
c.confirmedScid = auxData.realScid.Val
1222+
c.ConfirmationHeight = auxData.confirmationHeight.Val
12101223

12111224
auxData.memo.WhenSomeV(func(memo []byte) {
12121225
c.Memo = memo
@@ -1234,6 +1247,9 @@ func (c *OpenChannel) extractTlvData() openChannelTlvData {
12341247
realScid: tlv.NewRecordT[tlv.TlvType4](
12351248
c.confirmedScid,
12361249
),
1250+
confirmationHeight: tlv.NewPrimitiveRecord[tlv.TlvType8](
1251+
c.ConfirmationHeight,
1252+
),
12371253
}
12381254

12391255
if len(c.Memo) != 0 {
@@ -1501,6 +1517,37 @@ func (c *OpenChannel) fullSync(tx kvdb.RwTx) error {
15011517
return putOpenChannel(chanBucket, c)
15021518
}
15031519

1520+
// MarkConfirmationHeight updates the channel's confirmation height once the
1521+
// channel opening transaction receives one confirmation.
1522+
func (c *OpenChannel) MarkConfirmationHeight(height uint32) error {
1523+
c.Lock()
1524+
defer c.Unlock()
1525+
1526+
if err := kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
1527+
chanBucket, err := fetchChanBucketRw(
1528+
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
1529+
)
1530+
if err != nil {
1531+
return err
1532+
}
1533+
1534+
channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint)
1535+
if err != nil {
1536+
return err
1537+
}
1538+
1539+
channel.ConfirmationHeight = height
1540+
1541+
return putOpenChannel(chanBucket, channel)
1542+
}, func() {}); err != nil {
1543+
return err
1544+
}
1545+
1546+
c.ConfirmationHeight = height
1547+
1548+
return nil
1549+
}
1550+
15041551
// MarkAsOpen marks a channel as fully open given a locator that uniquely
15051552
// describes its location within the chain.
15061553
func (c *OpenChannel) MarkAsOpen(openLoc lnwire.ShortChannelID) error {

channeldb/channel_test.go

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,73 @@ func TestChannelStateTransition(t *testing.T) {
978978
require.Empty(t, fwdPkgs, "no forwarding packages should exist")
979979
}
980980

981+
// TestOpeningChannelTxConfirmation verifies that calling MarkConfirmationHeight
982+
// correctly updates the confirmed state. It also ensures that calling Refresh
983+
// on a different OpenChannel updates its in-memory state to reflect the prior
984+
// MarkConfirmationHeight call.
985+
func TestOpeningChannelTxConfirmation(t *testing.T) {
986+
t.Parallel()
987+
988+
fullDB, err := MakeTestDB(t)
989+
require.NoError(t, err)
990+
991+
cdb := fullDB.ChannelStateDB()
992+
993+
// Create a pending channel that was broadcast at height 99.
994+
const broadcastHeight = uint32(99)
995+
channelState := createTestChannel(
996+
t, cdb, pendingHeightOption(broadcastHeight),
997+
)
998+
999+
// Fetch pending channels from the database.
1000+
pendingChannels, err := cdb.FetchPendingChannels()
1001+
require.NoError(t, err)
1002+
require.Len(t, pendingChannels, 1)
1003+
1004+
// Verify the broadcast height of the pending channel.
1005+
require.Equal(
1006+
t, broadcastHeight, pendingChannels[0].FundingBroadcastHeight,
1007+
)
1008+
1009+
confirmationHeight := broadcastHeight + 1
1010+
1011+
// Mark the channel's confirmation height.
1012+
err = pendingChannels[0].MarkConfirmationHeight(confirmationHeight)
1013+
require.NoError(t, err)
1014+
1015+
// Verify the ConfirmationHeight is updated correctly.
1016+
require.Equal(
1017+
t, confirmationHeight, pendingChannels[0].ConfirmationHeight,
1018+
)
1019+
1020+
// Re-fetch the pending channels to confirm persistence.
1021+
pendingChannels, err = cdb.FetchPendingChannels()
1022+
require.NoError(t, err)
1023+
require.Len(t, pendingChannels, 1)
1024+
1025+
// Validate the confirmation and broadcast height.
1026+
require.Equal(
1027+
t, confirmationHeight, pendingChannels[0].ConfirmationHeight,
1028+
)
1029+
require.Equal(
1030+
t, broadcastHeight, pendingChannels[0].FundingBroadcastHeight,
1031+
)
1032+
1033+
// Ensure the original channel state's confirmation height is not
1034+
// updated before refresh.
1035+
require.EqualValues(t, channelState.ConfirmationHeight, 0)
1036+
1037+
// Refresh the original channel state.
1038+
err = channelState.Refresh()
1039+
require.NoError(t, err)
1040+
1041+
// Verify that both channel states now have the same ConfirmationHeight.
1042+
require.Equal(
1043+
t, channelState.ConfirmationHeight,
1044+
pendingChannels[0].ConfirmationHeight,
1045+
)
1046+
}
1047+
9811048
func TestFetchPendingChannels(t *testing.T) {
9821049
t.Parallel()
9831050

@@ -1007,7 +1074,7 @@ func TestFetchPendingChannels(t *testing.T) {
10071074
}
10081075

10091076
chanOpenLoc := lnwire.ShortChannelID{
1010-
BlockHeight: 5,
1077+
BlockHeight: broadcastHeight + 1,
10111078
TxIndex: 10,
10121079
TxPosition: 15,
10131080
}

0 commit comments

Comments
 (0)