channeldb: add new AMPInvoiceState field to store AMP sub-invoice metadata

In this commit, we add a new type `AMPInvoiceState` that's used to store
AMP sub-invoice meta data alongside the main invoice. This will be used
to allow changes to be made to an AMP invoices without reading out all
the HTLCs. In addition, callers can use this metadata to look up
information about the current sub-invoice state of AMP HTLCs.
This commit is contained in:
Olaoluwa Osuntokun committed 2021-10-28 15:50:02 -07:00
1 parent 8299d632e8
commit 65cca8dd1c
2 files changed
+431 -18

No files matched your search

+90 -1
View File
@@ -1,6 +1,7 @@
package channeldb
import (
"bytes"
"crypto/rand"
"fmt"
"math"
@@ -12,6 +13,7 @@ import (
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/tlv"
"github.com/stretchr/testify/require"
)
@@ -49,7 +51,8 @@ func randInvoice(value lnwire.MilliSatoshi) (*Invoice, error) {
Value: value,
Features: emptyFeatures,
},
Htlcs: map[CircuitKey]*InvoiceHTLC{},
Htlcs: map[CircuitKey]*InvoiceHTLC{},
AMPState: map[SetID]InvoiceStateAMP{},
}
i.Memo = []byte("memo")
@@ -2474,3 +2477,89 @@ func TestAddInvoiceInvalidFeatureDeps(t *testing.T) {
lnwire.PaymentAddrOptional,
))
}
// TestEncodeDecodeAmpInvoiceState asserts that the nested TLV
// encoding+decoding for the AMPInvoiceState struct works as expected.
func TestEncodeDecodeAmpInvoiceState(t *testing.T) {
t.Parallel()
setID1 := [32]byte{1}
setID2 := [32]byte{2}
setID3 := [32]byte{3}
circuitKey1 := CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 1,
}
circuitKey2 := CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 2,
}
circuitKey3 := CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 3,
}
// Make a sample invoice state map that we'll encode then decode to
// assert equality of.
ampState := AMPInvoiceState{
setID1: InvoiceStateAMP{
State: HtlcStateSettled,
SettleDate: testNow,
SettleIndex: 1,
InvoiceKeys: map[CircuitKey]struct{}{
circuitKey1: struct{}{},
circuitKey2: struct{}{},
},
},
setID2: InvoiceStateAMP{
State: HtlcStateCanceled,
SettleDate: testNow,
SettleIndex: 2,
InvoiceKeys: map[CircuitKey]struct{}{
circuitKey1: struct{}{},
},
},
setID3: InvoiceStateAMP{
State: HtlcStateAccepted,
SettleDate: testNow,
SettleIndex: 3,
InvoiceKeys: map[CircuitKey]struct{}{
circuitKey1: struct{}{},
circuitKey2: struct{}{},
circuitKey3: struct{}{},
},
},
}
// We'll now make a sample invoice stream, and use that to encode the
// amp state we created above.
tlvStream, err := tlv.NewStream(
tlv.MakeDynamicRecord(
invoiceAmpStateType, &ampState, ampState.recordSize,
ampStateEncoder, ampStateDecoder,
),
)
require.Nil(t, err)
// Next encode the stream into a set of raw bytes.
var b bytes.Buffer
err = tlvStream.Encode(&b)
require.Nil(t, err)
// Now create a new blank ampState map, which we'll use to decode the
// bytes into.
ampState2 := make(AMPInvoiceState)
// Decode from the raw stream into this blank mpa.
tlvStream, err = tlv.NewStream(
tlv.MakeDynamicRecord(
invoiceAmpStateType, &ampState2, nil,
ampStateEncoder, ampStateDecoder,
),
)
require.Nil(t, err)
err = tlvStream.Decode(&b)
require.Nil(t, err)
// The two states should match.
require.Equal(t, ampState, ampState2)
}