Skip to content

Commit dc59f4a

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 3802428 commit dc59f4a

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

channeldb/channel.go

+47
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

+78-1
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,83 @@ 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, "unable to make test database")
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, "unable to list pending channels")
1002+
require.Len(t, pendingChannels, 1, "expected one pending channel")
1003+
1004+
// Verify the broadcast height of the pending channel.
1005+
require.Equal(
1006+
t, broadcastHeight, pendingChannels[0].FundingBroadcastHeight,
1007+
"broadcast height mismatch",
1008+
)
1009+
1010+
confirmationHeight := broadcastHeight + 1
1011+
1012+
// Mark the channel's confirmation height.
1013+
err = pendingChannels[0].MarkConfirmationHeight(confirmationHeight)
1014+
require.NoError(t, err, "unable to mark channel's confirmation height")
1015+
1016+
// Verify the ConfirmationHeight is updated correctly.
1017+
require.Equal(
1018+
t, confirmationHeight, pendingChannels[0].ConfirmationHeight,
1019+
"channel confirmation height not updated correctly",
1020+
)
1021+
1022+
// Re-fetch the pending channels to confirm persistence.
1023+
pendingChannels, err = cdb.FetchPendingChannels()
1024+
require.NoError(t, err, "unable to list pending channels")
1025+
require.Len(t, pendingChannels, 1, "expected one pending channel")
1026+
1027+
// Validate the confirmation and broadcast height.
1028+
require.Equal(
1029+
t, confirmationHeight, pendingChannels[0].ConfirmationHeight,
1030+
"channel confirmation height mismatch after re-fetching",
1031+
)
1032+
require.Equal(
1033+
t, broadcastHeight, pendingChannels[0].FundingBroadcastHeight,
1034+
"broadcast height mismatch after re-fetching",
1035+
)
1036+
1037+
// Ensure the original channel state's confirmation height is not
1038+
// updated before refresh.
1039+
require.NotEqual(
1040+
t, channelState.ConfirmationHeight,
1041+
pendingChannels[0].ConfirmationHeight, "original channel "+
1042+
"state's ConfirmationHeight should not match before "+
1043+
"refresh",
1044+
)
1045+
1046+
// Refresh the original channel state.
1047+
err = channelState.Refresh()
1048+
require.NoError(t, err, "unable to refresh channel state")
1049+
1050+
// Verify that both channel states now have the same ConfirmationHeight.
1051+
require.Equal(
1052+
t, channelState.ConfirmationHeight,
1053+
pendingChannels[0].ConfirmationHeight,
1054+
"channel ConfirmationHeight mismatch after refresh",
1055+
)
1056+
}
1057+
9811058
func TestFetchPendingChannels(t *testing.T) {
9821059
t.Parallel()
9831060

@@ -1007,7 +1084,7 @@ func TestFetchPendingChannels(t *testing.T) {
10071084
}
10081085

10091086
chanOpenLoc := lnwire.ShortChannelID{
1010-
BlockHeight: 5,
1087+
BlockHeight: broadcastHeight + 1,
10111088
TxIndex: 10,
10121089
TxPosition: 15,
10131090
}

0 commit comments

Comments
 (0)