channeldb: final htlc resolution storage opt-in
This commit is contained in:
10 files changed
+85
-27
No files matched your search
+24
-15
@@ -1879,12 +1879,18 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the bucket where settled htlcs are recorded.
|
// Get the bucket where settled htlcs are recorded if the user
|
||||||
finalHtlcsBucket, err := fetchFinalHtlcsBucketRw(
|
// opted in to storing this information.
|
||||||
tx, c.ShortChannelID,
|
var finalHtlcsBucket kvdb.RwBucket
|
||||||
)
|
if c.Db.parent.storeFinalHtlcResolutions {
|
||||||
if err != nil {
|
bucket, err := fetchFinalHtlcsBucketRw(
|
||||||
return err
|
tx, c.ShortChannelID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
finalHtlcsBucket = bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
var unsignedUpdates []LogUpdate
|
var unsignedUpdates []LogUpdate
|
||||||
@@ -1957,15 +1963,18 @@ func processFinalHtlc(finalHtlcsBucket walletdb.ReadWriteBucket, upd LogUpdate,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := putFinalHtlc(
|
// Store the final resolution in the database if a bucket is provided.
|
||||||
finalHtlcsBucket, id,
|
if finalHtlcsBucket != nil {
|
||||||
FinalHtlcInfo{
|
err := putFinalHtlc(
|
||||||
Settled: settled,
|
finalHtlcsBucket, id,
|
||||||
Offchain: true,
|
FinalHtlcInfo{
|
||||||
},
|
Settled: settled,
|
||||||
)
|
Offchain: true,
|
||||||
if err != nil {
|
},
|
||||||
return err
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finalHtlcs[id] = settled
|
finalHtlcs[id] = settled
|
||||||
|
|||||||
@@ -1463,7 +1463,7 @@ func TestKeyLocatorEncoding(t *testing.T) {
|
|||||||
func TestFinalHtlcs(t *testing.T) {
|
func TestFinalHtlcs(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
fullDB, err := MakeTestDB(t)
|
fullDB, err := MakeTestDB(t, OptionStoreFinalHtlcResolutions(true))
|
||||||
require.NoError(t, err, "unable to make test database")
|
require.NoError(t, err, "unable to make test database")
|
||||||
|
|
||||||
cdb := fullDB.ChannelStateDB()
|
cdb := fullDB.ChannelStateDB()
|
||||||
|
|||||||
@@ -307,6 +307,7 @@ type DB struct {
|
|||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
dryRun bool
|
dryRun bool
|
||||||
keepFailedPaymentAttempts bool
|
keepFailedPaymentAttempts bool
|
||||||
|
storeFinalHtlcResolutions bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens or creates channeldb. Any necessary schemas migrations due
|
// Open opens or creates channeldb. Any necessary schemas migrations due
|
||||||
@@ -364,6 +365,7 @@ func CreateWithBackend(backend kvdb.Backend,
|
|||||||
clock: opts.clock,
|
clock: opts.clock,
|
||||||
dryRun: opts.dryRun,
|
dryRun: opts.dryRun,
|
||||||
keepFailedPaymentAttempts: opts.keepFailedPaymentAttempts,
|
keepFailedPaymentAttempts: opts.keepFailedPaymentAttempts,
|
||||||
|
storeFinalHtlcResolutions: opts.storeFinalHtlcResolutions,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the parent pointer (only used in tests).
|
// Set the parent pointer (only used in tests).
|
||||||
@@ -1741,6 +1743,11 @@ func (c *ChannelStateDB) LookupFinalHtlc(chanID lnwire.ShortChannelID,
|
|||||||
func (c *ChannelStateDB) PutOnchainFinalHtlcOutcome(
|
func (c *ChannelStateDB) PutOnchainFinalHtlcOutcome(
|
||||||
chanID lnwire.ShortChannelID, htlcID uint64, settled bool) error {
|
chanID lnwire.ShortChannelID, htlcID uint64, settled bool) error {
|
||||||
|
|
||||||
|
// Skip if the user did not opt in to storing final resolutions.
|
||||||
|
if !c.parent.storeFinalHtlcResolutions {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return kvdb.Update(c.backend, func(tx kvdb.RwTx) error {
|
return kvdb.Update(c.backend, func(tx kvdb.RwTx) error {
|
||||||
finalHtlcsBucket, err := fetchFinalHtlcsBucketRw(tx, chanID)
|
finalHtlcsBucket, err := fetchFinalHtlcsBucketRw(tx, chanID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ type Options struct {
|
|||||||
// keepFailedPaymentAttempts determines whether failed htlc attempts
|
// keepFailedPaymentAttempts determines whether failed htlc attempts
|
||||||
// are kept on disk or removed to save space.
|
// are kept on disk or removed to save space.
|
||||||
keepFailedPaymentAttempts bool
|
keepFailedPaymentAttempts bool
|
||||||
|
|
||||||
|
// storeFinalHtlcResolutions determines whether to persistently store
|
||||||
|
// the final resolution of incoming htlcs.
|
||||||
|
storeFinalHtlcResolutions bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultOptions returns an Options populated with default values.
|
// DefaultOptions returns an Options populated with default values.
|
||||||
@@ -187,6 +191,16 @@ func OptionKeepFailedPaymentAttempts(keepFailedPaymentAttempts bool) OptionModif
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OptionStoreFinalHtlcResolutions controls whether to persistently store the
|
||||||
|
// final resolution of incoming htlcs.
|
||||||
|
func OptionStoreFinalHtlcResolutions(
|
||||||
|
storeFinalHtlcResolutions bool) OptionModifier {
|
||||||
|
|
||||||
|
return func(o *Options) {
|
||||||
|
o.storeFinalHtlcResolutions = storeFinalHtlcResolutions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// OptionPruneRevocationLog specifies whether the migration for pruning
|
// OptionPruneRevocationLog specifies whether the migration for pruning
|
||||||
// revocation logs needs to be applied or not.
|
// revocation logs needs to be applied or not.
|
||||||
func OptionPruneRevocationLog(prune bool) OptionModifier {
|
func OptionPruneRevocationLog(prune bool) OptionModifier {
|
||||||
|
|||||||
@@ -372,6 +372,8 @@ type Config struct {
|
|||||||
|
|
||||||
KeepFailedPaymentAttempts bool `long:"keep-failed-payment-attempts" description:"Keeps persistent record of all failed payment attempts for successfully settled payments."`
|
KeepFailedPaymentAttempts bool `long:"keep-failed-payment-attempts" description:"Keeps persistent record of all failed payment attempts for successfully settled payments."`
|
||||||
|
|
||||||
|
StoreFinalHtlcResolutions bool `long:"store-final-htlc-resolutions" description:"Persistently store the final resolution of incoming htlcs."`
|
||||||
|
|
||||||
DefaultRemoteMaxHtlcs uint16 `long:"default-remote-max-htlcs" description:"The default max_htlc applied when opening or accepting channels. This value limits the number of concurrent HTLCs that the remote party can add to the commitment. The maximum possible value is 483."`
|
DefaultRemoteMaxHtlcs uint16 `long:"default-remote-max-htlcs" description:"The default max_htlc applied when opening or accepting channels. This value limits the number of concurrent HTLCs that the remote party can add to the commitment. The maximum possible value is 483."`
|
||||||
|
|
||||||
NumGraphSyncPeers int `long:"numgraphsyncpeers" description:"The number of peers that we should receive new graph updates from. This option can be tuned to save bandwidth for light clients or routing nodes."`
|
NumGraphSyncPeers int `long:"numgraphsyncpeers" description:"The number of peers that we should receive new graph updates from. This option can be tuned to save bandwidth for light clients or routing nodes."`
|
||||||
|
|||||||
@@ -872,6 +872,9 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
|
|||||||
channeldb.OptionDryRunMigration(cfg.DryRunMigration),
|
channeldb.OptionDryRunMigration(cfg.DryRunMigration),
|
||||||
channeldb.OptionSetUseGraphCache(!cfg.DB.NoGraphCache),
|
channeldb.OptionSetUseGraphCache(!cfg.DB.NoGraphCache),
|
||||||
channeldb.OptionKeepFailedPaymentAttempts(cfg.KeepFailedPaymentAttempts),
|
channeldb.OptionKeepFailedPaymentAttempts(cfg.KeepFailedPaymentAttempts),
|
||||||
|
channeldb.OptionStoreFinalHtlcResolutions(
|
||||||
|
cfg.StoreFinalHtlcResolutions,
|
||||||
|
),
|
||||||
channeldb.OptionPruneRevocationLog(cfg.DB.PruneRevocation),
|
channeldb.OptionPruneRevocationLog(cfg.DB.PruneRevocation),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ current gossip sync query status.
|
|||||||
Final resolution data will only be available for htlcs that are resolved
|
Final resolution data will only be available for htlcs that are resolved
|
||||||
after upgrading lnd.
|
after upgrading lnd.
|
||||||
|
|
||||||
|
This feature is [opt-in](https://github.com/lightningnetwork/lnd/pull/7341)
|
||||||
|
via a config flag.
|
||||||
|
|
||||||
* Zero-amount private invoices [now provide hop
|
* Zero-amount private invoices [now provide hop
|
||||||
hints](https://github.com/lightningnetwork/lnd/pull/7082), up to `maxHopHints`
|
hints](https://github.com/lightningnetwork/lnd/pull/7082), up to `maxHopHints`
|
||||||
(20 currently).
|
(20 currently).
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ func assertOutputExistsByValue(t *testing.T, commitTx *wire.MsgTx,
|
|||||||
|
|
||||||
// testAddSettleWorkflow tests a simple channel scenario where Alice and Bob
|
// testAddSettleWorkflow tests a simple channel scenario where Alice and Bob
|
||||||
// add, the settle an HTLC between themselves.
|
// add, the settle an HTLC between themselves.
|
||||||
func testAddSettleWorkflow(t *testing.T, tweakless bool) {
|
func testAddSettleWorkflow(t *testing.T, tweakless,
|
||||||
|
storeFinalHtlcResolutions bool) {
|
||||||
|
|
||||||
// Create a test channel which will be used for the duration of this
|
// 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,
|
// unittest. The channel will be funded evenly with Alice having 5 BTC,
|
||||||
// and Bob having 5 BTC.
|
// and Bob having 5 BTC.
|
||||||
@@ -68,7 +70,12 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool) {
|
|||||||
chanType = channeldb.SingleFunderBit
|
chanType = channeldb.SingleFunderBit
|
||||||
}
|
}
|
||||||
|
|
||||||
aliceChannel, bobChannel, err := CreateTestChannels(t, chanType)
|
aliceChannel, bobChannel, err := CreateTestChannels(
|
||||||
|
t, chanType,
|
||||||
|
channeldb.OptionStoreFinalHtlcResolutions(
|
||||||
|
storeFinalHtlcResolutions,
|
||||||
|
),
|
||||||
|
)
|
||||||
require.NoError(t, err, "unable to create test channels")
|
require.NoError(t, err, "unable to create test channels")
|
||||||
|
|
||||||
paymentPreimage := bytes.Repeat([]byte{1}, 32)
|
paymentPreimage := bytes.Repeat([]byte{1}, 32)
|
||||||
@@ -248,13 +255,18 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool) {
|
|||||||
for htlcID, settled := range finalHtlcs {
|
for htlcID, settled := range finalHtlcs {
|
||||||
require.True(t, settled, "final settle expected")
|
require.True(t, settled, "final settle expected")
|
||||||
|
|
||||||
// Assert that final resolution was stored in Bob's database.
|
// Assert that final resolution was stored in Bob's database if
|
||||||
|
// storage is enabled.
|
||||||
finalInfo, err := bobChannel.channelState.Db.LookupFinalHtlc(
|
finalInfo, err := bobChannel.channelState.Db.LookupFinalHtlc(
|
||||||
bobChannel.ShortChanID(), htlcID,
|
bobChannel.ShortChanID(), htlcID,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
if storeFinalHtlcResolutions {
|
||||||
require.True(t, finalInfo.Offchain)
|
require.NoError(t, err)
|
||||||
require.True(t, finalInfo.Settled)
|
require.True(t, finalInfo.Offchain)
|
||||||
|
require.True(t, finalInfo.Settled)
|
||||||
|
} else {
|
||||||
|
require.ErrorIs(t, err, channeldb.ErrHtlcUnknown)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fwdPkg, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation2)
|
fwdPkg, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation2)
|
||||||
@@ -339,9 +351,13 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
|
|||||||
for _, tweakless := range []bool{true, false} {
|
for _, tweakless := range []bool{true, false} {
|
||||||
tweakless := tweakless
|
tweakless := tweakless
|
||||||
t.Run(fmt.Sprintf("tweakless=%v", tweakless), func(t *testing.T) {
|
t.Run(fmt.Sprintf("tweakless=%v", tweakless), func(t *testing.T) {
|
||||||
testAddSettleWorkflow(t, tweakless)
|
testAddSettleWorkflow(t, tweakless, false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Run("storeFinalHtlcResolutions=true", func(t *testing.T) {
|
||||||
|
testAddSettleWorkflow(t, false, true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestChannelZeroAddLocalHeight tests that we properly set the addCommitHeightLocal
|
// TestChannelZeroAddLocalHeight tests that we properly set the addCommitHeightLocal
|
||||||
|
|||||||
@@ -106,8 +106,9 @@ var (
|
|||||||
// allocated to each side. Within the channel, Alice is the initiator. If
|
// allocated to each side. Within the channel, Alice is the initiator. If
|
||||||
// tweaklessCommits is true, then the commits within the channels will use the
|
// tweaklessCommits is true, then the commits within the channels will use the
|
||||||
// new format, otherwise the legacy format.
|
// new format, otherwise the legacy format.
|
||||||
func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType) (
|
func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType,
|
||||||
*LightningChannel, *LightningChannel, error) {
|
dbModifiers ...channeldb.OptionModifier) (*LightningChannel,
|
||||||
|
*LightningChannel, error) {
|
||||||
|
|
||||||
channelCapacity, err := btcutil.NewAmount(testChannelCapacity)
|
channelCapacity, err := btcutil.NewAmount(testChannelCapacity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -228,7 +229,7 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType) (
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dbAlice, err := channeldb.Open(t.TempDir())
|
dbAlice, err := channeldb.Open(t.TempDir(), dbModifiers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -236,7 +237,7 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType) (
|
|||||||
require.NoError(t, dbAlice.Close())
|
require.NoError(t, dbAlice.Close())
|
||||||
})
|
})
|
||||||
|
|
||||||
dbBob, err := channeldb.Open(t.TempDir())
|
dbBob, err := channeldb.Open(t.TempDir(), dbModifiers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,6 +315,9 @@
|
|||||||
; settled payments.
|
; settled payments.
|
||||||
; keep-failed-payment-attempts=false
|
; keep-failed-payment-attempts=false
|
||||||
|
|
||||||
|
; Persistently store the final resolution of incoming htlcs.
|
||||||
|
; store-final-htlc-resolutions=false
|
||||||
|
|
||||||
; The default max_htlc applied when opening or accepting channels. This value
|
; The default max_htlc applied when opening or accepting channels. This value
|
||||||
; limits the number of concurrent HTLCs that the remote party can add to the
|
; limits the number of concurrent HTLCs that the remote party can add to the
|
||||||
; commitment. The maximum possible value is 483.
|
; commitment. The maximum possible value is 483.
|
||||||
|
|||||||
Reference in new issue
Block a user