multi: create channeldb/models package

Add a new subpackage to `lnd/channeldb` to hold some of the types that
are used in the package itself and in other packages that should not
depend on `channeldb`.
This commit is contained in:
positiveblue committed 2023-01-16 07:14:55 -08:00
1 parent c602ac07e7
commit 383cb40f8d
29 files changed
+400 -315

No files matched your search

+5 -77
View File
@@ -17,6 +17,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
@@ -177,11 +178,6 @@ var (
// tolerant.
ErrNoPendingCommit = fmt.Errorf("no pending commits found")
// ErrInvalidCircuitKeyLen signals that a circuit key could not be
// decoded because the byte slice is of an invalid length.
ErrInvalidCircuitKeyLen = fmt.Errorf(
"length of serialized circuit key must be 16 bytes")
// ErrNoCommitPoint is returned when no data loss commit point is found
// in the database.
ErrNoCommitPoint = fmt.Errorf("no commit point found")
@@ -2156,74 +2152,6 @@ func deserializeLogUpdate(r io.Reader) (*LogUpdate, error) {
return l, nil
}
// CircuitKey is used by a channel to uniquely identify the HTLCs it receives
// from the switch, and is used to purge our in-memory state of HTLCs that have
// already been processed by a link. Two list of CircuitKeys are included in
// each CommitDiff to allow a link to determine which in-memory htlcs directed
// the opening and closing of circuits in the switch's circuit map.
type CircuitKey struct {
// ChanID is the short chanid indicating the HTLC's origin.
//
// NOTE: It is fine for this value to be blank, as this indicates a
// locally-sourced payment.
ChanID lnwire.ShortChannelID
// HtlcID is the unique htlc index predominately assigned by links,
// though can also be assigned by switch in the case of locally-sourced
// payments.
HtlcID uint64
}
// SetBytes deserializes the given bytes into this CircuitKey.
func (k *CircuitKey) SetBytes(bs []byte) error {
if len(bs) != 16 {
return ErrInvalidCircuitKeyLen
}
k.ChanID = lnwire.NewShortChanIDFromInt(
binary.BigEndian.Uint64(bs[:8]))
k.HtlcID = binary.BigEndian.Uint64(bs[8:])
return nil
}
// Bytes returns the serialized bytes for this circuit key.
func (k CircuitKey) Bytes() []byte {
bs := make([]byte, 16)
binary.BigEndian.PutUint64(bs[:8], k.ChanID.ToUint64())
binary.BigEndian.PutUint64(bs[8:], k.HtlcID)
return bs
}
// Encode writes a CircuitKey to the provided io.Writer.
func (k *CircuitKey) Encode(w io.Writer) error {
var scratch [16]byte
binary.BigEndian.PutUint64(scratch[:8], k.ChanID.ToUint64())
binary.BigEndian.PutUint64(scratch[8:], k.HtlcID)
_, err := w.Write(scratch[:])
return err
}
// Decode reads a CircuitKey from the provided io.Reader.
func (k *CircuitKey) Decode(r io.Reader) error {
var scratch [16]byte
if _, err := io.ReadFull(r, scratch[:]); err != nil {
return err
}
k.ChanID = lnwire.NewShortChanIDFromInt(
binary.BigEndian.Uint64(scratch[:8]))
k.HtlcID = binary.BigEndian.Uint64(scratch[8:])
return nil
}
// String returns a string representation of the CircuitKey.
func (k CircuitKey) String() string {
return fmt.Sprintf("(Chan ID=%s, HTLC ID=%d)", k.ChanID, k.HtlcID)
}
// CommitDiff represents the delta needed to apply the state transition between
// two subsequent commitment states. Given state N and state N+1, one is able
// to apply the set of messages contained within the CommitDiff to N to arrive
@@ -2252,13 +2180,13 @@ type CommitDiff struct {
// Add packets included in this commitment txn. After a restart, this
// set of htlcs is acked from the link's incoming mailbox to ensure
// there isn't an attempt to re-add them to this commitment txn.
OpenedCircuitKeys []CircuitKey
OpenedCircuitKeys []models.CircuitKey
// ClosedCircuitKeys records the unique identifiers for any settle/fail
// packets that were resolved by this commitment txn. After a restart,
// this is used to ensure those circuits are removed from the circuit
// map, and the downstream packets in the link's mailbox are removed.
ClosedCircuitKeys []CircuitKey
ClosedCircuitKeys []models.CircuitKey
// AddAcks specifies the locations (commit height, pkg index) of any
// Adds that were failed/settled in this commit diff. This will ack
@@ -2387,7 +2315,7 @@ func deserializeCommitDiff(r io.Reader) (*CommitDiff, error) {
return nil, err
}
d.OpenedCircuitKeys = make([]CircuitKey, numOpenRefs)
d.OpenedCircuitKeys = make([]models.CircuitKey, numOpenRefs)
for i := 0; i < int(numOpenRefs); i++ {
err := ReadElements(r,
&d.OpenedCircuitKeys[i].ChanID,
@@ -2402,7 +2330,7 @@ func deserializeCommitDiff(r io.Reader) (*CommitDiff, error) {
return nil, err
}
d.ClosedCircuitKeys = make([]CircuitKey, numClosedRefs)
d.ClosedCircuitKeys = make([]models.CircuitKey, numClosedRefs)
for i := 0; i < int(numClosedRefs); i++ {
err := ReadElements(r,
&d.ClosedCircuitKeys[i].ChanID,
+3 -2
View File
@@ -14,6 +14,7 @@ import (
"github.com/btcsuite/btcd/wire"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb"
@@ -716,8 +717,8 @@ func TestChannelStateTransition(t *testing.T) {
},
},
},
OpenedCircuitKeys: []CircuitKey{},
ClosedCircuitKeys: []CircuitKey{},
OpenedCircuitKeys: []models.CircuitKey{},
ClosedCircuitKeys: []models.CircuitKey{},
}
copy(commitDiff.LogUpdates[0].UpdateMsg.(*lnwire.UpdateAddHTLC).PaymentHash[:],
bytes.Repeat([]byte{1}, 32))
+100 -77
View File
@@ -8,6 +8,7 @@ import (
"testing"
"time"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/lntypes"
@@ -51,7 +52,7 @@ func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) {
Value: value,
Features: emptyFeatures,
},
Htlcs: map[CircuitKey]*InvoiceHTLC{},
Htlcs: map[models.CircuitKey]*InvoiceHTLC{},
AMPState: map[SetID]InvoiceStateAMP{},
}
i.Memo = []byte("memo")
@@ -77,7 +78,7 @@ func settleTestInvoice(invoice *Invoice, settleIndex uint64) {
invoice.SettleDate = testNow
invoice.AmtPaid = invoice.Terms.Value
invoice.State = ContractSettled
invoice.Htlcs[CircuitKey{}] = &InvoiceHTLC{
invoice.Htlcs[models.CircuitKey{}] = &InvoiceHTLC{
Amt: invoice.Terms.Value,
AcceptTime: testNow,
ResolveTime: testNow,
@@ -433,7 +434,7 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) {
paymentHash := preimage.Hash()
testInvoice := &Invoice{
Htlcs: map[CircuitKey]*InvoiceHTLC{},
Htlcs: map[models.CircuitKey]*InvoiceHTLC{},
Terms: ContractTerm{
Value: lnwire.NewMSatFromSatoshis(10000),
Features: emptyFeatures,
@@ -446,7 +447,10 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) {
}
// Accept an htlc on this invoice.
key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4}
key := models.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(1),
HtlcID: 4,
}
htlc := HtlcAcceptDesc{
Amt: 500,
CustomRecords: make(record.CustomSet),
@@ -456,7 +460,7 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) {
invoice, err := db.UpdateInvoice(ref, nil,
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
AddHtlcs: map[models.CircuitKey]*HtlcAcceptDesc{
key: &htlc,
},
}, nil
@@ -473,7 +477,7 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) {
invoice, err = db.UpdateInvoice(ref, nil,
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
CancelHtlcs: map[CircuitKey]struct{}{
CancelHtlcs: map[models.CircuitKey]struct{}{
key: {},
},
}, nil
@@ -542,7 +546,7 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
_, err = db.UpdateInvoice(ref, (*SetID)(setID1),
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
CancelHtlcs: map[CircuitKey]struct{}{
CancelHtlcs: map[models.CircuitKey]struct{}{
{HtlcID: 0}: {},
},
SetID: (*SetID)(setID1),
@@ -562,28 +566,29 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
invoice.State = ContractOpen
invoice.AmtPaid = 2 * amt
invoice.SettleDate = dbInvoice.SettleDate
invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
invoice.Htlcs = map[models.CircuitKey]*InvoiceHTLC{
{HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID1, payHash, &preimage),
{HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, payHash, &preimage),
{HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, payHash, &preimage),
}
invoice.AMPState[*setID1] = InvoiceStateAMP{
State: HtlcStateCanceled,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
{HtlcID: 0}: {},
},
}
invoice.AMPState[*setID2] = InvoiceStateAMP{
State: HtlcStateAccepted,
AmtPaid: amt * 2,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
{HtlcID: 1}: {},
{HtlcID: 2}: {},
},
}
invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateCanceled
invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0)
htlc0 := models.CircuitKey{HtlcID: 0}
invoice.Htlcs[htlc0].State = HtlcStateCanceled
invoice.Htlcs[htlc0].ResolveTime = time.Unix(1, 0)
require.Equal(t, invoice, dbInvoice)
@@ -592,7 +597,7 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
_, err = db.UpdateInvoice(ref, (*SetID)(setID2),
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
CancelHtlcs: map[CircuitKey]struct{}{
CancelHtlcs: map[models.CircuitKey]struct{}{
{HtlcID: 1}: {},
},
SetID: (*SetID)(setID2),
@@ -604,8 +609,9 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
require.Nil(t, err)
dbInvoice = &freshInvoice
invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateCanceled
invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0)
htlc1 := models.CircuitKey{HtlcID: 1}
invoice.Htlcs[htlc1].State = HtlcStateCanceled
invoice.Htlcs[htlc1].ResolveTime = time.Unix(1, 0)
invoice.AmtPaid = amt
ampState := invoice.AMPState[*setID2]
@@ -620,7 +626,7 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
_, err = db.UpdateInvoice(ref, (*SetID)(setID2),
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
CancelHtlcs: map[CircuitKey]struct{}{
CancelHtlcs: map[models.CircuitKey]struct{}{
{HtlcID: 2}: {},
},
SetID: (*SetID)(setID2),
@@ -636,8 +642,9 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
ampState.AmtPaid = 0
invoice.AMPState[*setID2] = ampState
invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateCanceled
invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0)
htlc2 := models.CircuitKey{HtlcID: 2}
invoice.Htlcs[htlc2].State = HtlcStateCanceled
invoice.Htlcs[htlc2].ResolveTime = time.Unix(1, 0)
invoice.AmtPaid = 0
require.Equal(t, invoice, dbInvoice)
@@ -865,7 +872,7 @@ func TestSettleIndexAmpPayments(t *testing.T) {
require.Equal(t, 1, len(invoiceFiltered.Htlcs))
// The set ID for the HTLC should match the queried set ID.
key := CircuitKey{HtlcID: uint64(i + 1)}
key := models.CircuitKey{HtlcID: uint64(i + 1)}
htlc := invoiceFiltered.Htlcs[key]
require.Equal(t, *setID, htlc.AMP.Record.SetID())
@@ -878,21 +885,21 @@ func TestSettleIndexAmpPayments(t *testing.T) {
_, err = db.UpdateInvoice(
ref, (*SetID)(setID1),
getUpdateInvoiceAMPSettle(
setID1, preimage, CircuitKey{HtlcID: 1},
setID1, preimage, models.CircuitKey{HtlcID: 1},
),
)
require.Nil(t, err)
_, err = db.UpdateInvoice(
ref, (*SetID)(setID2),
getUpdateInvoiceAMPSettle(
setID2, preimage, CircuitKey{HtlcID: 2},
setID2, preimage, models.CircuitKey{HtlcID: 2},
),
)
require.Nil(t, err)
_, err = db.UpdateInvoice(
ref, (*SetID)(setID3),
getUpdateInvoiceAMPSettle(
setID3, preimage, CircuitKey{HtlcID: 3},
setID3, preimage, models.CircuitKey{HtlcID: 3},
),
)
require.Nil(t, err)
@@ -931,7 +938,7 @@ func TestSettleIndexAmpPayments(t *testing.T) {
require.Equal(t, subInvoiceState.State, HtlcStateSettled)
require.Equal(t, int(subInvoiceState.SettleIndex), i+1)
invoiceKey := CircuitKey{HtlcID: uint64(i + 1)}
invoiceKey := models.CircuitKey{HtlcID: uint64(i + 1)}
_, keyFound := subInvoiceState.InvoiceKeys[invoiceKey]
require.True(t, keyFound)
}
@@ -1043,7 +1050,7 @@ func TestDuplicateSettleInvoice(t *testing.T) {
invoice.State = ContractSettled
invoice.AmtPaid = amt
invoice.SettleDate = dbInvoice.SettleDate
invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
invoice.Htlcs = map[models.CircuitKey]*InvoiceHTLC{
{}: {
Amt: amt,
AcceptTime: time.Unix(1, 0),
@@ -1484,7 +1491,7 @@ func getUpdateInvoice(amt lnwire.MilliSatoshi) InvoiceUpdateCallback {
Preimage: invoice.Terms.PaymentPreimage,
NewState: ContractSettled,
},
AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
AddHtlcs: map[models.CircuitKey]*HtlcAcceptDesc{
{}: {
Amt: amt,
CustomRecords: noRecords,
@@ -1508,7 +1515,7 @@ func TestCustomRecords(t *testing.T) {
paymentHash := preimage.Hash()
testInvoice := &Invoice{
Htlcs: map[CircuitKey]*InvoiceHTLC{},
Htlcs: map[models.CircuitKey]*InvoiceHTLC{},
Terms: ContractTerm{
Value: lnwire.NewMSatFromSatoshis(10000),
Features: emptyFeatures,
@@ -1521,7 +1528,10 @@ func TestCustomRecords(t *testing.T) {
}
// Accept an htlc with custom records on this invoice.
key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4}
key := models.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(1),
HtlcID: 4,
}
records := record.CustomSet{
100000: []byte{},
@@ -1531,14 +1541,14 @@ func TestCustomRecords(t *testing.T) {
ref := InvoiceRefByHash(paymentHash)
_, err = db.UpdateInvoice(ref, nil,
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
key: {
Amt: 500,
CustomRecords: records,
},
htlcs := map[models.CircuitKey]*HtlcAcceptDesc{
key: {
Amt: 500,
CustomRecords: records,
},
}, nil
}
return &InvoiceUpdateDesc{AddHtlcs: htlcs}, nil
},
)
require.NoError(t, err, "unable to add invoice htlc")
@@ -1585,7 +1595,10 @@ func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) {
require.Nil(t, err)
// Accept an htlc with custom records on this invoice.
key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4}
key := models.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(1),
HtlcID: 4,
}
records := make(map[uint64][]byte)
var ampData *InvoiceHtlcAMPData
@@ -1603,15 +1616,14 @@ func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) {
ref := InvoiceRefByHash(payHash)
_, err = db.UpdateInvoice(ref, nil,
func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
return &InvoiceUpdateDesc{
AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
key: {
Amt: 500,
AMP: ampData,
CustomRecords: records,
},
htlcs := map[models.CircuitKey]*HtlcAcceptDesc{
key: {
Amt: 500,
AMP: ampData,
CustomRecords: records,
},
}, nil
}
return &InvoiceUpdateDesc{AddHtlcs: htlcs}, nil
},
)
require.Nil(t, err)
@@ -1667,7 +1679,7 @@ func TestInvoiceRef(t *testing.T) {
// sets.
func TestHTLCSet(t *testing.T) {
inv := &Invoice{
Htlcs: make(map[CircuitKey]*InvoiceHTLC),
Htlcs: make(map[models.CircuitKey]*InvoiceHTLC),
}
// Construct two distinct set id's, in this test we'll also track the
@@ -1677,9 +1689,9 @@ func TestHTLCSet(t *testing.T) {
// Create the expected htlc sets for each group, these will be updated
// as the invoice is modified.
expSetNil := make(map[CircuitKey]*InvoiceHTLC)
expSet1 := make(map[CircuitKey]*InvoiceHTLC)
expSet2 := make(map[CircuitKey]*InvoiceHTLC)
expSetNil := make(map[models.CircuitKey]*InvoiceHTLC)
expSet1 := make(map[models.CircuitKey]*InvoiceHTLC)
expSet2 := make(map[models.CircuitKey]*InvoiceHTLC)
checkHTLCSets := func() {
require.Equal(t, expSetNil, inv.HTLCSet(nil, HtlcStateAccepted))
@@ -1722,7 +1734,7 @@ func TestHTLCSet(t *testing.T) {
}
// Add the HTLC to the invoice's set of HTLCs.
key := CircuitKey{HtlcID: uint64(i)}
key := models.CircuitKey{HtlcID: uint64(i)}
htlc := &InvoiceHTLC{
AMP: ampData,
State: h.state,
@@ -1757,7 +1769,7 @@ func TestAddInvoiceWithHTLCs(t *testing.T) {
testInvoice, err := randInvoice(1000)
require.Nil(t, err)
key := CircuitKey{HtlcID: 1}
key := models.CircuitKey{HtlcID: 1}
testInvoice.Htlcs[key] = &InvoiceHTLC{}
payHash := testInvoice.Terms.PaymentPreimage.Hash()
@@ -1802,14 +1814,14 @@ func TestSetIDIndex(t *testing.T) {
invoice.State = ContractOpen
invoice.AmtPaid = amt
invoice.SettleDate = dbInvoice.SettleDate
invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
invoice.Htlcs = map[models.CircuitKey]*InvoiceHTLC{
{HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, payHash, &preimage),
}
invoice.AMPState = map[SetID]InvoiceStateAMP{}
invoice.AMPState[*setID] = InvoiceStateAMP{
State: HtlcStateAccepted,
AmtPaid: amt,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
{HtlcID: 0}: {},
},
}
@@ -1860,7 +1872,7 @@ func TestSetIDIndex(t *testing.T) {
invoice.State = ContractOpen
invoice.AmtPaid += 2 * amt
invoice.SettleDate = dbInvoice.SettleDate
invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
invoice.Htlcs = map[models.CircuitKey]*InvoiceHTLC{
{HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, payHash, &preimage),
{HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, payHash, nil),
{HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, payHash, nil),
@@ -1868,14 +1880,14 @@ func TestSetIDIndex(t *testing.T) {
invoice.AMPState[*setID] = InvoiceStateAMP{
State: HtlcStateAccepted,
AmtPaid: amt,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
{HtlcID: 0}: {},
},
}
invoice.AMPState[*setID2] = InvoiceStateAMP{
State: HtlcStateAccepted,
AmtPaid: amt * 2,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
{HtlcID: 1}: {},
{HtlcID: 2}: {},
},
@@ -1901,7 +1913,10 @@ func TestSetIDIndex(t *testing.T) {
// zero setID so it isn't used for anything internally.
_, err = db.UpdateInvoice(
ref, nil,
getUpdateInvoiceAMPSettle(&[32]byte{}, [32]byte{}, CircuitKey{HtlcID: 99}),
getUpdateInvoiceAMPSettle(
&[32]byte{}, [32]byte{},
models.CircuitKey{HtlcID: 99},
),
)
require.Equal(t, ErrEmptyHTLCSet, err)
@@ -1910,7 +1925,9 @@ func TestSetIDIndex(t *testing.T) {
// invoice to be settled multiple times.
_, err = db.UpdateInvoice(
ref, (*SetID)(setID),
getUpdateInvoiceAMPSettle(setID, preimage, CircuitKey{HtlcID: 0}),
getUpdateInvoiceAMPSettle(
setID, preimage, models.CircuitKey{HtlcID: 0},
),
)
require.Nil(t, err)
@@ -1931,8 +1948,9 @@ func TestSetIDIndex(t *testing.T) {
invoice.AMPState[*setID] = ampState
invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateSettled
invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0)
htlc0 := models.CircuitKey{HtlcID: 0}
invoice.Htlcs[htlc0].State = HtlcStateSettled
invoice.Htlcs[htlc0].ResolveTime = time.Unix(1, 0)
require.Equal(t, invoice, dbInvoice)
@@ -1940,7 +1958,9 @@ func TestSetIDIndex(t *testing.T) {
// error, as it's already been settled.
_, err = db.UpdateInvoice(
ref, (*SetID)(setID),
getUpdateInvoiceAMPSettle(setID, preimage, CircuitKey{HtlcID: 0}),
getUpdateInvoiceAMPSettle(
setID, preimage, models.CircuitKey{HtlcID: 0},
),
)
require.Equal(t, ErrEmptyHTLCSet, err)
@@ -1951,7 +1971,8 @@ func TestSetIDIndex(t *testing.T) {
_, err = db.UpdateInvoice(
ref, (*SetID)(setID2),
getUpdateInvoiceAMPSettle(
setID2, preimage, CircuitKey{HtlcID: 1}, CircuitKey{HtlcID: 2},
setID2, preimage, models.CircuitKey{HtlcID: 1},
models.CircuitKey{HtlcID: 2},
),
)
require.Nil(t, err)
@@ -1968,13 +1989,15 @@ func TestSetIDIndex(t *testing.T) {
invoice.AMPState[*setID2] = ampState
invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateSettled
invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0)
invoice.Htlcs[CircuitKey{HtlcID: 1}].AMP.Preimage = &preimage
htlc1 := models.CircuitKey{HtlcID: 1}
htlc2 := models.CircuitKey{HtlcID: 2}
invoice.Htlcs[htlc1].State = HtlcStateSettled
invoice.Htlcs[htlc1].ResolveTime = time.Unix(1, 0)
invoice.Htlcs[htlc1].AMP.Preimage = &preimage
invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateSettled
invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0)
invoice.Htlcs[CircuitKey{HtlcID: 2}].AMP.Preimage = &preimage
invoice.Htlcs[htlc2].State = HtlcStateSettled
invoice.Htlcs[htlc2].ResolveTime = time.Unix(1, 0)
invoice.Htlcs[htlc2].AMP.Preimage = &preimage
require.Equal(t, invoice, dbInvoice)
@@ -2033,7 +2056,7 @@ func updateAcceptAMPHtlc(id uint64, amt lnwire.MilliSatoshi,
}
update := &InvoiceUpdateDesc{
State: state,
AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
AddHtlcs: map[models.CircuitKey]*HtlcAcceptDesc{
{HtlcID: id}: {
Amt: amt,
CustomRecords: noRecords,
@@ -2046,15 +2069,15 @@ func updateAcceptAMPHtlc(id uint64, amt lnwire.MilliSatoshi,
}
}
func getUpdateInvoiceAMPSettle(setID *[32]byte,
preimage [32]byte, circuitKeys ...CircuitKey) InvoiceUpdateCallback {
func getUpdateInvoiceAMPSettle(setID *[32]byte, preimage [32]byte,
circuitKeys ...models.CircuitKey) InvoiceUpdateCallback {
return func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
if invoice.State == ContractSettled {
return nil, ErrInvoiceAlreadySettled
}
preImageSet := make(map[CircuitKey]lntypes.Preimage)
preImageSet := make(map[models.CircuitKey]lntypes.Preimage)
for _, key := range circuitKeys {
preImageSet[key] = preimage
}
@@ -2164,7 +2187,7 @@ func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) {
)
require.Nil(t, err)
htlcPreimages := make(map[CircuitKey]lntypes.Preimage)
htlcPreimages := make(map[models.CircuitKey]lntypes.Preimage)
for key := range dbInvoice.Htlcs {
// Set the either the same preimage used to accept above, or a
// blank preimage depending on the test case.
@@ -2980,13 +3003,13 @@ func TestEncodeDecodeAmpInvoiceState(t *testing.T) {
setID2 := [32]byte{2}
setID3 := [32]byte{3}
circuitKey1 := CircuitKey{
circuitKey1 := models.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 1,
}
circuitKey2 := CircuitKey{
circuitKey2 := models.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 2,
}
circuitKey3 := CircuitKey{
circuitKey3 := models.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 3,
}
@@ -2997,7 +3020,7 @@ func TestEncodeDecodeAmpInvoiceState(t *testing.T) {
State: HtlcStateSettled,
SettleDate: testNow,
SettleIndex: 1,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
circuitKey1: {},
circuitKey2: {},
},
@@ -3007,7 +3030,7 @@ func TestEncodeDecodeAmpInvoiceState(t *testing.T) {
State: HtlcStateCanceled,
SettleDate: testNow,
SettleIndex: 2,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
circuitKey1: {},
},
AmtPaid: 6,
@@ -3016,7 +3039,7 @@ func TestEncodeDecodeAmpInvoiceState(t *testing.T) {
State: HtlcStateAccepted,
SettleDate: testNow,
SettleIndex: 3,
InvoiceKeys: map[CircuitKey]struct{}{
InvoiceKeys: map[models.CircuitKey]struct{}{
circuitKey1: {},
circuitKey2: {},
circuitKey3: {},
+58 -48
View File
@@ -9,6 +9,7 @@ import (
"strings"
"time"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/kvdb"
@@ -485,7 +486,7 @@ type InvoiceStateAMP struct {
// InvoiceKeys is the set of circuit keys that can be used to locate
// the invoices for a given set ID.
InvoiceKeys map[CircuitKey]struct{}
InvoiceKeys map[models.CircuitKey]struct{}
// AmtPaid is the total amount that was paid in the AMP sub-invoice.
// Fetching the full HTLC/invoice state allows one to extract the
@@ -499,7 +500,7 @@ func (i *InvoiceStateAMP) copy() (InvoiceStateAMP, error) {
result := *i
// Make a copy of the InvoiceKeys map.
result.InvoiceKeys = make(map[CircuitKey]struct{})
result.InvoiceKeys = make(map[models.CircuitKey]struct{})
for k := range i.InvoiceKeys {
result.InvoiceKeys[k] = struct{}{}
}
@@ -608,7 +609,7 @@ type Invoice struct {
// Htlcs records all htlcs that paid to this invoice. Some of these
// htlcs may have been marked as canceled.
Htlcs map[CircuitKey]*InvoiceHTLC
Htlcs map[models.CircuitKey]*InvoiceHTLC
// AMPState describes the state of any related sub-invoices AMP to this
// greater invoice. A sub-invoice is defined by a set of HTLCs with the
@@ -627,8 +628,10 @@ type Invoice struct {
// case of legacy or MPP, and no HTLCs in the case of AMP. Otherwise, the
// returned set will be filtered by the populated setID which is used to
// retrieve AMP HTLC sets.
func (i *Invoice) HTLCSet(setID *[32]byte, state HtlcState) map[CircuitKey]*InvoiceHTLC {
htlcSet := make(map[CircuitKey]*InvoiceHTLC)
func (i *Invoice) HTLCSet(setID *[32]byte,
state HtlcState) map[models.CircuitKey]*InvoiceHTLC {
htlcSet := make(map[models.CircuitKey]*InvoiceHTLC)
for key, htlc := range i.Htlcs {
// Only add HTLCs that are in the requested HtlcState.
if htlc.State != state {
@@ -649,9 +652,9 @@ func (i *Invoice) HTLCSet(setID *[32]byte, state HtlcState) map[CircuitKey]*Invo
// are in the target state. Passing a nil setID will return no invoices, since
// all MPP HTLCs are part of the same HTLC set.
func (i *Invoice) HTLCSetCompliment(setID *[32]byte,
state HtlcState) map[CircuitKey]*InvoiceHTLC {
state HtlcState) map[models.CircuitKey]*InvoiceHTLC {
htlcSet := make(map[CircuitKey]*InvoiceHTLC)
htlcSet := make(map[models.CircuitKey]*InvoiceHTLC)
for key, htlc := range i.Htlcs {
// Only add HTLCs that are in the requested HtlcState.
if htlc.State != state {
@@ -845,11 +848,11 @@ type InvoiceUpdateDesc struct {
State *InvoiceStateUpdateDesc
// CancelHtlcs describes the htlcs that need to be canceled.
CancelHtlcs map[CircuitKey]struct{}
CancelHtlcs map[models.CircuitKey]struct{}
// AddHtlcs describes the newly accepted htlcs that need to be added to
// the invoice.
AddHtlcs map[CircuitKey]*HtlcAcceptDesc
AddHtlcs map[models.CircuitKey]*HtlcAcceptDesc
// SetID is an optional set ID for AMP invoices that allows operations
// to be more efficient by ensuring we don't need to read out the
@@ -868,7 +871,7 @@ type InvoiceStateUpdateDesc struct {
// HTLCPreimages set the HTLC-level preimages stored for AMP HTLCs.
// These are only learned when settling the invoice as a whole. Must be
// set when settling an invoice with non-nil SetID.
HTLCPreimages map[CircuitKey]lntypes.Preimage
HTLCPreimages map[models.CircuitKey]lntypes.Preimage
// SetID identifies a specific set of HTLCs destined for the same
// invoice as part of a larger AMP payment. This value will be nil for
@@ -1729,7 +1732,9 @@ func serializeInvoice(w io.Writer, i *Invoice) error {
// serializeHtlcs serializes a map containing circuit keys and invoice htlcs to
// a writer.
func serializeHtlcs(w io.Writer, htlcs map[CircuitKey]*InvoiceHTLC) error {
func serializeHtlcs(w io.Writer,
htlcs map[models.CircuitKey]*InvoiceHTLC) error {
for key, htlc := range htlcs {
// Encode the htlc in a tlv stream.
chanID := key.ChanID.ToUint64()
@@ -1831,10 +1836,10 @@ func getNanoTime(ns uint64) time.Time {
// fetchFilteredAmpInvoices retrieves only a select set of AMP invoices
// identified by the setID value.
func fetchFilteredAmpInvoices(invoiceBucket kvdb.RBucket,
invoiceNum []byte, setIDs ...*SetID) (map[CircuitKey]*InvoiceHTLC, error) {
func fetchFilteredAmpInvoices(invoiceBucket kvdb.RBucket, invoiceNum []byte,
setIDs ...*SetID) (map[models.CircuitKey]*InvoiceHTLC, error) {
htlcs := make(map[CircuitKey]*InvoiceHTLC)
htlcs := make(map[models.CircuitKey]*InvoiceHTLC)
for _, setID := range setIDs {
invoiceSetIDKey := makeInvoiceSetIDKey(invoiceNum, setID[:])
@@ -1899,8 +1904,8 @@ func forEachAMPInvoice(invoiceBucket kvdb.RBucket, invoiceNum []byte,
// AMP bucket to find all the individual HTLCs (by setID) associated with a
// given invoice. If a list of set IDs are specified, then only HTLCs
// associated with that setID will be retrieved.
func fetchAmpSubInvoices(invoiceBucket kvdb.RBucket,
invoiceNum []byte, setIDs ...*SetID) (map[CircuitKey]*InvoiceHTLC, error) {
func fetchAmpSubInvoices(invoiceBucket kvdb.RBucket, invoiceNum []byte,
setIDs ...*SetID) (map[models.CircuitKey]*InvoiceHTLC, error) {
// If a set of setIDs was specified, then we can skip the cursor and
// just read out exactly what we need.
@@ -1912,20 +1917,21 @@ func fetchAmpSubInvoices(invoiceBucket kvdb.RBucket,
// Otherwise, iterate over all the htlc sets that are prefixed beside
// this invoice in the main invoice bucket.
htlcs := make(map[CircuitKey]*InvoiceHTLC)
err := forEachAMPInvoice(invoiceBucket, invoiceNum, func(key, htlcSet []byte) error {
htlcSetReader := bytes.NewReader(htlcSet)
htlcsBySetID, err := deserializeHtlcs(htlcSetReader)
if err != nil {
return err
}
htlcs := make(map[models.CircuitKey]*InvoiceHTLC)
err := forEachAMPInvoice(invoiceBucket, invoiceNum,
func(key, htlcSet []byte) error {
htlcSetReader := bytes.NewReader(htlcSet)
htlcsBySetID, err := deserializeHtlcs(htlcSetReader)
if err != nil {
return err
}
for key, htlc := range htlcsBySetID {
htlcs[key] = htlc
}
for key, htlc := range htlcsBySetID {
htlcs[key] = htlc
}
return nil
})
return nil
})
if err != nil {
return nil, err
}
@@ -2130,7 +2136,7 @@ func deserializeInvoice(r io.Reader) (Invoice, error) {
}
func encodeCircuitKeys(w io.Writer, val interface{}, buf *[8]byte) error {
if v, ok := val.(*map[CircuitKey]struct{}); ok {
if v, ok := val.(*map[models.CircuitKey]struct{}); ok {
// We encode the set of circuit keys as a varint length prefix.
// followed by a series of fixed sized uint8 integers.
numKeys := uint64(len(*v))
@@ -2156,8 +2162,10 @@ func encodeCircuitKeys(w io.Writer, val interface{}, buf *[8]byte) error {
return tlv.NewTypeForEncodingErr(val, "*map[CircuitKey]struct{}")
}
func decodeCircuitKeys(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
if v, ok := val.(*map[CircuitKey]struct{}); ok {
func decodeCircuitKeys(r io.Reader, val interface{}, buf *[8]byte,
l uint64) error {
if v, ok := val.(*map[models.CircuitKey]struct{}); ok {
// First, we'll read out the varint that encodes the number of
// circuit keys encoded.
numKeys, err := tlv.ReadVarInt(r, buf)
@@ -2169,7 +2177,7 @@ func decodeCircuitKeys(r io.Reader, val interface{}, buf *[8]byte, l uint64) err
// one until we're done.
for i := uint64(0); i < numKeys; i++ {
var (
key CircuitKey
key models.CircuitKey
scid uint64
)
@@ -2309,8 +2317,10 @@ func ampStateDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error
htlcState uint8
settleIndex uint64
settleDateBytes []byte
invoiceKeys = make(map[CircuitKey]struct{})
amtPaid uint64
invoiceKeys = make(
map[models.CircuitKey]struct{},
)
amtPaid uint64
)
tlvStream, err := tlv.NewStream(
tlv.MakePrimitiveRecord(
@@ -2367,8 +2377,8 @@ func ampStateDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error
// deserializeHtlcs reads a list of invoice htlcs from a reader and returns it
// as a map.
func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) {
htlcs := make(map[CircuitKey]*InvoiceHTLC)
func deserializeHtlcs(r io.Reader) (map[models.CircuitKey]*InvoiceHTLC, error) {
htlcs := make(map[models.CircuitKey]*InvoiceHTLC)
for {
// Read the length of the tlv stream for this htlc.
@@ -2388,7 +2398,7 @@ func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) {
// Decode the contents into the htlc fields.
var (
htlc InvoiceHTLC
key CircuitKey
key models.CircuitKey
chanID uint64
state uint8
acceptTime, resolveTime uint64
@@ -2485,7 +2495,7 @@ func copyInvoice(src *Invoice) (*Invoice, error) {
State: src.State,
AmtPaid: src.AmtPaid,
Htlcs: make(
map[CircuitKey]*InvoiceHTLC, len(src.Htlcs),
map[models.CircuitKey]*InvoiceHTLC, len(src.Htlcs),
),
AMPState: make(map[SetID]InvoiceStateAMP),
HodlInvoice: src.HodlInvoice,
@@ -2540,7 +2550,7 @@ func makeInvoiceSetIDKey(invoiceNum, setID []byte) [invoiceSetIDKeyLen]byte {
// potentially massive HTLC set, and also allows us to quickly find the HLTCs
// associated with a particular HTLC set.
func updateAMPInvoices(invoiceBucket kvdb.RwBucket, invoiceNum []byte,
htlcsToUpdate map[SetID]map[CircuitKey]*InvoiceHTLC) error {
htlcsToUpdate map[SetID]map[models.CircuitKey]*InvoiceHTLC) error {
for setID, htlcSet := range htlcsToUpdate {
// First write out the set of HTLCs including all the relevant TLV
@@ -2567,8 +2577,8 @@ func updateAMPInvoices(invoiceBucket kvdb.RwBucket, invoiceNum []byte,
// set ID), and update sthe internal AMP state of an invoice, and also tallies
// the set of HTLCs to be updated on disk.
func updateHtlcsAmp(invoice *Invoice,
updateMap map[SetID]map[CircuitKey]*InvoiceHTLC, htlc *InvoiceHTLC,
setID SetID, circuitKey CircuitKey) {
updateMap map[SetID]map[models.CircuitKey]*InvoiceHTLC,
htlc *InvoiceHTLC, setID SetID, circuitKey models.CircuitKey) {
ampState, ok := invoice.AMPState[setID]
if !ok {
@@ -2576,7 +2586,7 @@ func updateHtlcsAmp(invoice *Invoice,
// we'll need to create it.
ampState = InvoiceStateAMP{
State: HtlcStateAccepted,
InvoiceKeys: make(map[CircuitKey]struct{}),
InvoiceKeys: make(map[models.CircuitKey]struct{}),
}
}
@@ -2605,8 +2615,8 @@ func updateHtlcsAmp(invoice *Invoice,
// apply the new update to the update MAP, since all the HTLCs for a given HTLC
// set need to be written in-line with each other.
func cancelHtlcsAmp(invoice *Invoice,
updateMap map[SetID]map[CircuitKey]*InvoiceHTLC, htlc *InvoiceHTLC,
circuitKey CircuitKey) {
updateMap map[SetID]map[models.CircuitKey]*InvoiceHTLC,
htlc *InvoiceHTLC, circuitKey models.CircuitKey) {
setID := htlc.AMP.Record.SetID()
@@ -2649,8 +2659,8 @@ func cancelHtlcsAmp(invoice *Invoice,
// that this HTLC set needs to be re-written back to disk.
func settleHtlcsAmp(invoice *Invoice,
settledSetIDs map[SetID]struct{},
updateMap map[SetID]map[CircuitKey]*InvoiceHTLC, htlc *InvoiceHTLC,
circuitKey CircuitKey) {
updateMap map[SetID]map[models.CircuitKey]*InvoiceHTLC,
htlc *InvoiceHTLC, circuitKey models.CircuitKey) {
// First, add the set ID to the set that was settled in this invoice
// update. We'll use this later to update the settle index.
@@ -2668,7 +2678,7 @@ func settleHtlcsAmp(invoice *Invoice,
// Finally, we'll add this to the set of HTLCs that need to be updated.
if _, ok := updateMap[setID]; !ok {
updateMap[setID] = make(map[CircuitKey]*InvoiceHTLC)
updateMap[setID] = make(map[models.CircuitKey]*InvoiceHTLC)
}
updateMap[setID][circuitKey] = htlc
}
@@ -2735,7 +2745,7 @@ func (d *DB) updateInvoice(hash *lntypes.Hash, refSetID *SetID, invoices,
)
// Process add actions from update descriptor.
htlcsAmpUpdate := make(map[SetID]map[CircuitKey]*InvoiceHTLC)
htlcsAmpUpdate := make(map[SetID]map[models.CircuitKey]*InvoiceHTLC)
for key, htlcUpdate := range update.AddHtlcs {
if _, exists := invoice.Htlcs[key]; exists {
return nil, fmt.Errorf("duplicate add of htlc %v", key)
+92
View File
@@ -0,0 +1,92 @@
package models
import (
"encoding/binary"
"fmt"
"io"
"github.com/lightningnetwork/lnd/lnwire"
)
const (
// serializedCircuitKeyLen is the exact length needed to encode a
// serialized CircuitKey.
serializedCircuitKeyLen = 16
)
var (
// ErrInvalidCircuitKeyLen signals that a circuit key could not be
// decoded because the byte slice is of an invalid length.
ErrInvalidCircuitKeyLen = fmt.Errorf("length of serialized circuit " +
"key must be 16 bytes")
)
// CircuitKey is used by a channel to uniquely identify the HTLCs it receives
// from the switch, and is used to purge our in-memory state of HTLCs that have
// already been processed by a link. Two list of CircuitKeys are included in
// each CommitDiff to allow a link to determine which in-memory htlcs directed
// the opening and closing of circuits in the switch's circuit map.
type CircuitKey struct {
// ChanID is the short chanid indicating the HTLC's origin.
//
// NOTE: It is fine for this value to be blank, as this indicates a
// locally-sourced payment.
ChanID lnwire.ShortChannelID
// HtlcID is the unique htlc index predominately assigned by links,
// though can also be assigned by switch in the case of locally-sourced
// payments.
HtlcID uint64
}
// SetBytes deserializes the given bytes into this CircuitKey.
func (k *CircuitKey) SetBytes(bs []byte) error {
if len(bs) != serializedCircuitKeyLen {
return ErrInvalidCircuitKeyLen
}
k.ChanID = lnwire.NewShortChanIDFromInt(
binary.BigEndian.Uint64(bs[:8]))
k.HtlcID = binary.BigEndian.Uint64(bs[8:])
return nil
}
// Bytes returns the serialized bytes for this circuit key.
func (k CircuitKey) Bytes() []byte {
bs := make([]byte, serializedCircuitKeyLen)
binary.BigEndian.PutUint64(bs[:8], k.ChanID.ToUint64())
binary.BigEndian.PutUint64(bs[8:], k.HtlcID)
return bs
}
// Encode writes a CircuitKey to the provided io.Writer.
func (k *CircuitKey) Encode(w io.Writer) error {
var scratch [serializedCircuitKeyLen]byte
binary.BigEndian.PutUint64(scratch[:8], k.ChanID.ToUint64())
binary.BigEndian.PutUint64(scratch[8:], k.HtlcID)
_, err := w.Write(scratch[:])
return err
}
// Decode reads a CircuitKey from the provided io.Reader.
func (k *CircuitKey) Decode(r io.Reader) error {
var scratch [serializedCircuitKeyLen]byte
if _, err := io.ReadFull(r, scratch[:]); err != nil {
return err
}
k.ChanID = lnwire.NewShortChanIDFromInt(
binary.BigEndian.Uint64(scratch[:8]))
k.HtlcID = binary.BigEndian.Uint64(scratch[8:])
return nil
}
// String returns a string representation of the CircuitKey.
func (k CircuitKey) String() string {
return fmt.Sprintf("(Chan ID=%s, HTLC ID=%d)", k.ChanID, k.HtlcID)
}