Skip to content

Commit

Permalink
Merge pull request lightningnetwork#8159 from carlaKC/7298-1-forwardb…
Browse files Browse the repository at this point in the history
…lindedroutes

[1/3]: Preparatory work for Forwarding Blinded Routes
  • Loading branch information
Roasbeef authored Mar 28, 2024
2 parents 41cdb0f + 2130022 commit 1d61de2
Show file tree
Hide file tree
Showing 26 changed files with 1,262 additions and 160 deletions.
68 changes: 67 additions & 1 deletion channeldb/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const (
// begins to be interpreted as an absolute block height, rather than a
// relative one.
AbsoluteThawHeightThreshold uint32 = 500000

// HTLCBlindingPointTLV is the tlv type used for storing blinding
// points with HTLCs.
HTLCBlindingPointTLV tlv.Type = 0
)

var (
Expand Down Expand Up @@ -2316,7 +2320,56 @@ type HTLC struct {
// Note that this extra data is stored inline with the OnionBlob for
// legacy reasons, see serialization/deserialization functions for
// detail.
ExtraData []byte
ExtraData lnwire.ExtraOpaqueData

// BlindingPoint is an optional blinding point included with the HTLC.
//
// Note: this field is not a part of on-disk representation of the
// HTLC. It is stored in the ExtraData field, which is used to store
// a TLV stream of additional information associated with the HTLC.
BlindingPoint lnwire.BlindingPointRecord
}

// serializeExtraData encodes a TLV stream of extra data to be stored with a
// HTLC. It uses the update_add_htlc TLV types, because this is where extra
// data is passed with a HTLC. At present blinding points are the only extra
// data that we will store, and the function is a no-op if a nil blinding
// point is provided.
//
// This function MUST be called to persist all HTLC values when they are
// serialized.
func (h *HTLC) serializeExtraData() error {
var records []tlv.RecordProducer
h.BlindingPoint.WhenSome(func(b tlv.RecordT[lnwire.BlindingPointTlvType,
*btcec.PublicKey]) {

records = append(records, &b)
})

return h.ExtraData.PackRecords(records...)
}

// deserializeExtraData extracts TLVs from the extra data persisted for the
// htlc and populates values in the struct accordingly.
//
// This function MUST be called to populate the struct properly when HTLCs
// are deserialized.
func (h *HTLC) deserializeExtraData() error {
if len(h.ExtraData) == 0 {
return nil
}

blindingPoint := h.BlindingPoint.Zero()
tlvMap, err := h.ExtraData.ExtractRecords(&blindingPoint)
if err != nil {
return err
}

if val, ok := tlvMap[h.BlindingPoint.TlvType()]; ok && val == nil {
h.BlindingPoint = tlv.SomeRecordT(blindingPoint)
}

return nil
}

// SerializeHtlcs writes out the passed set of HTLC's into the passed writer
Expand All @@ -2340,6 +2393,12 @@ func SerializeHtlcs(b io.Writer, htlcs ...HTLC) error {
}

for _, htlc := range htlcs {
// Populate TLV stream for any additional fields contained
// in the TLV.
if err := htlc.serializeExtraData(); err != nil {
return err
}

// The onion blob and hltc data are stored as a single var
// bytes blob.
onionAndExtraData := make(
Expand Down Expand Up @@ -2425,6 +2484,12 @@ func DeserializeHtlcs(r io.Reader) ([]HTLC, error) {
onionAndExtraData[lnwire.OnionPacketSize:],
)
}

// Finally, deserialize any TLVs contained in that extra data
// if they are present.
if err := htlcs[i].deserializeExtraData(); err != nil {
return nil, err
}
}

return htlcs, nil
Expand All @@ -2440,6 +2505,7 @@ func (h *HTLC) Copy() HTLC {
}
copy(clone.Signature[:], h.Signature)
copy(clone.RHash[:], h.RHash[:])
copy(clone.ExtraData, h.ExtraData)

return clone
}
Expand Down
71 changes: 37 additions & 34 deletions channeldb/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/lightningnetwork/lnd/lntest/channels"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
"github.com/lightningnetwork/lnd/tlv"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -651,8 +652,7 @@ func TestChannelStateTransition(t *testing.T) {
{
LogIndex: 2,
UpdateMsg: &lnwire.UpdateAddHTLC{
ChanID: lnwire.ChannelID{1, 2, 3},
ExtraData: make([]byte, 0),
ChanID: lnwire.ChannelID{1, 2, 3},
},
},
}
Expand Down Expand Up @@ -710,25 +710,22 @@ func TestChannelStateTransition(t *testing.T) {
wireSig,
wireSig,
},
ExtraData: make([]byte, 0),
},
LogUpdates: []LogUpdate{
{
LogIndex: 1,
UpdateMsg: &lnwire.UpdateAddHTLC{
ID: 1,
Amount: lnwire.NewMSatFromSatoshis(100),
Expiry: 25,
ExtraData: make([]byte, 0),
ID: 1,
Amount: lnwire.NewMSatFromSatoshis(100),
Expiry: 25,
},
},
{
LogIndex: 2,
UpdateMsg: &lnwire.UpdateAddHTLC{
ID: 2,
Amount: lnwire.NewMSatFromSatoshis(200),
Expiry: 50,
ExtraData: make([]byte, 0),
ID: 2,
Amount: lnwire.NewMSatFromSatoshis(200),
Expiry: 50,
},
},
},
Expand Down Expand Up @@ -1610,9 +1607,25 @@ func TestHTLCsExtraData(t *testing.T) {
OnionBlob: lnmock.MockOnion(),
}

// Add a blinding point to a htlc.
blindingPointHTLC := HTLC{
Signature: testSig.Serialize(),
Incoming: false,
Amt: 10,
RHash: key,
RefundTimeout: 1,
OnionBlob: lnmock.MockOnion(),
BlindingPoint: tlv.SomeRecordT(
tlv.NewPrimitiveRecord[lnwire.BlindingPointTlvType](
pubKey,
),
),
}

testCases := []struct {
name string
htlcs []HTLC
name string
htlcs []HTLC
blindingIdx int
}{
{
// Serialize multiple HLTCs with no extra data to
Expand All @@ -1624,30 +1637,12 @@ func TestHTLCsExtraData(t *testing.T) {
},
},
{
// Some HTLCs with extra data, some without.
name: "mixed extra data",
htlcs: []HTLC{
mockHtlc,
{
Signature: testSig.Serialize(),
Incoming: false,
Amt: 10,
RHash: key,
RefundTimeout: 1,
OnionBlob: lnmock.MockOnion(),
ExtraData: []byte{1, 2, 3},
},
blindingPointHTLC,
mockHtlc,
{
Signature: testSig.Serialize(),
Incoming: false,
Amt: 10,
RHash: key,
RefundTimeout: 1,
OnionBlob: lnmock.MockOnion(),
ExtraData: bytes.Repeat(
[]byte{9}, 999,
),
},
},
},
}
Expand All @@ -1665,7 +1660,15 @@ func TestHTLCsExtraData(t *testing.T) {
r := bytes.NewReader(b.Bytes())
htlcs, err := DeserializeHtlcs(r)
require.NoError(t, err)
require.Equal(t, testCase.htlcs, htlcs)

require.EqualValues(t, len(testCase.htlcs), len(htlcs))
for i, htlc := range htlcs {
// We use the extra data field when we
// serialize, so we set to nil to be able to
// assert on equal for the test.
htlc.ExtraData = nil
require.Equal(t, testCase.htlcs[i], htlc)
}
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/lncli/cmd_payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -1250,9 +1250,9 @@ func parseBlindedPaymentParameters(ctx *cli.Context) (
BaseFeeMsat: ctx.Uint64(
blindedBaseFlag.Name,
),
ProportionalFeeMsat: ctx.Uint64(
ProportionalFeeRate: uint32(ctx.Uint64(
blindedPPMFlag.Name,
),
)),
TotalCltvDelta: uint32(ctx.Uint64(
blindedCLTVFlag.Name,
)),
Expand Down
13 changes: 12 additions & 1 deletion contractcourt/htlc_incoming_contest_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/txscript"
"github.com/lightningnetwork/lnd/channeldb"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/queue"
"github.com/lightningnetwork/lnd/tlv"
)

// htlcIncomingContestResolver is a ContractResolver that's able to resolve an
Expand Down Expand Up @@ -520,9 +522,18 @@ func (h *htlcIncomingContestResolver) Supplement(htlc channeldb.HTLC) {
func (h *htlcIncomingContestResolver) decodePayload() (*hop.Payload,
[]byte, error) {

var blindingPoint *btcec.PublicKey
h.htlc.BlindingPoint.WhenSome(
func(b tlv.RecordT[lnwire.BlindingPointTlvType,
*btcec.PublicKey]) {

blindingPoint = b.Val
},
)

onionReader := bytes.NewReader(h.htlc.OnionBlob[:])
iterator, err := h.OnionProcessor.ReconstructHopIterator(
onionReader, h.htlc.RHash[:],
onionReader, h.htlc.RHash[:], blindingPoint,
)
if err != nil {
return nil, nil, err
Expand Down
5 changes: 3 additions & 2 deletions contractcourt/htlc_incoming_contest_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"
"testing"

"github.com/btcsuite/btcd/btcec/v2"
sphinx "github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
Expand Down Expand Up @@ -288,8 +289,8 @@ type mockOnionProcessor struct {
offeredOnionBlob []byte
}

func (o *mockOnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte) (
hop.Iterator, error) {
func (o *mockOnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte,
blindingPoint *btcec.PublicKey) (hop.Iterator, error) {

data, err := ioutil.ReadAll(r)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion contractcourt/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"io"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channeldb/models"
Expand Down Expand Up @@ -40,7 +41,8 @@ type Registry interface {
type OnionProcessor interface {
// ReconstructHopIterator attempts to decode a valid sphinx packet from
// the passed io.Reader instance.
ReconstructHopIterator(r io.Reader, rHash []byte) (hop.Iterator, error)
ReconstructHopIterator(r io.Reader, rHash []byte,
blindingKey *btcec.PublicKey) (hop.Iterator, error)
}

// UtxoSweeper defines the sweep functions that contract court requires.
Expand Down
3 changes: 3 additions & 0 deletions docs/release-notes/release-notes-0.18.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@
* When computing a minimum fee for transaction construction, `lnd` [now takes our
bitcoin peers' feefilter values into account](https://github.com/lightningnetwork/lnd/pull/8418).

* [Preparatory work](https://github.com/lightningnetwork/lnd/pull/8159) for
forwarding of blinded routes was added.

## RPC Additions

* [Deprecated](https://github.com/lightningnetwork/lnd/pull/7175)
Expand Down
Loading

0 comments on commit 1d61de2

Please sign in to comment.