From 4521894ed2df667ddfb107fe4d33c08fb25f5676 Mon Sep 17 00:00:00 2001 From: Alex Sears Date: Mon, 11 Sep 2023 22:05:51 -0400 Subject: [PATCH 1/2] channeldb: Serialize/deserialize AMP struct in hop The AMP struct in a hop was never being set when deserizlied. Also, the AMP TLV record was not being added when the hop was serialized. This sets the TLV record when serializing and correctly sets the AMP struct on the hop when that record is present. Co-authored-by: BitcoinCoderBob <90647227+BitcoinCoderBob@users.noreply.github.com> Co-authored-by: Tee8z --- channeldb/payments.go | 22 +++++++++++++++++++++- channeldb/payments_test.go | 14 ++++++++++++++ docs/release-notes/release-notes-0.18.0.md | 5 +++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/channeldb/payments.go b/channeldb/payments.go index 800c877e1..c2d32ee8a 100644 --- a/channeldb/payments.go +++ b/channeldb/payments.go @@ -1157,6 +1157,10 @@ func serializeHop(w io.Writer, h *route.Hop) error { )) } + if h.AMP != nil { + records = append(records, h.AMP.Record()) + } + if h.Metadata != nil { records = append(records, record.NewMetadataRecord(&h.Metadata)) } @@ -1301,7 +1305,23 @@ func deserializeHop(r io.Reader) (*route.Hop, error) { } } - // If the metatdata type is present, remove it from the tlv map and + ampType := uint64(record.AMPOnionType) + if ampBytes, ok := tlvMap[ampType]; ok { + delete(tlvMap, ampType) + + var ( + amp = &record.AMP{} + ampRec = amp.Record() + r = bytes.NewReader(ampBytes) + ) + err := ampRec.Decode(r, uint64(len(ampBytes))) + if err != nil { + return nil, err + } + h.AMP = amp + } + + // If the metadata type is present, remove it from the tlv map and // populate directly on the hop. metadataType := uint64(record.MetadataOnionType) if metadata, ok := tlvMap[metadataType]; ok { diff --git a/channeldb/payments_test.go b/channeldb/payments_test.go index 8507268e4..37a7e30e7 100644 --- a/channeldb/payments_test.go +++ b/channeldb/payments_test.go @@ -44,11 +44,25 @@ var ( LegacyPayload: true, } + testHop3 = &route.Hop{ + PubKeyBytes: route.NewVertex(pub), + ChannelID: 12345, + OutgoingTimeLock: 111, + AmtToForward: 555, + CustomRecords: record.CustomSet{ + 65536: []byte{}, + 80001: []byte{}, + }, + AMP: record.NewAMP([32]byte{0x69}, [32]byte{0x42}, 1), + Metadata: []byte{1, 2, 3}, + } + testRoute = route.Route{ TotalTimeLock: 123, TotalAmount: 1234567, SourcePubKey: vertex, Hops: []*route.Hop{ + testHop3, testHop2, testHop1, }, diff --git a/docs/release-notes/release-notes-0.18.0.md b/docs/release-notes/release-notes-0.18.0.md index 0d48ab63f..d9884c2d8 100644 --- a/docs/release-notes/release-notes-0.18.0.md +++ b/docs/release-notes/release-notes-0.18.0.md @@ -53,6 +53,8 @@ walletrpc endpoint `RemoveTransaction` is introduced which let one easily remove unconfirmed transaction manually. +* The AMP struct in payment hops will [now be populated](https://github.com/lightningnetwork/lnd/pull/7976) when the AMP TLV is set. + # New Features ## Functional Enhancements @@ -203,6 +205,7 @@ * Amin Bashiri * Andras Banki-Horvath +* BitcoinerCoderBob * Carla Kirk-Cohen * Elle Mouton * ErikEk @@ -210,6 +213,8 @@ * Marcos Fernandez Perez * Matt Morehouse * Slyghtning +* Tee8z * Turtle * Ononiwu Maureen Chiamaka +* w3irdrobot * Yong Yu From 0767a2cbc00da248407870267987619da17e12a6 Mon Sep 17 00:00:00 2001 From: Alex Sears Date: Fri, 26 Jan 2024 15:21:43 -0500 Subject: [PATCH 2/2] routerrpc: unmarshal AMP record in route hop marshalling --- itest/lnd_amp_test.go | 10 ++++++++++ lnrpc/routerrpc/router_backend.go | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/itest/lnd_amp_test.go b/itest/lnd_amp_test.go index a76aedd99..bbf5cb543 100644 --- a/itest/lnd_amp_test.go +++ b/itest/lnd_amp_test.go @@ -410,6 +410,16 @@ func testSendPaymentAMP(ht *lntest.HarnessTest) { if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED { succeeded++ } + + // When an AMP record is expected, it will only be seen on the + // last hop of a route. So we make sure it isn't set on any of + // the hops except the last one + for _, hop := range htlc.Route.Hops[:len(htlc.Route.Hops)-1] { + require.Nil(ht, hop.AmpRecord) + } + + lastHop := htlc.Route.Hops[len(htlc.Route.Hops)-1] + require.NotNil(ht, lastHop.AmpRecord) } const minExpectedShards = 3 diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index 49d080a32..640333734 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -613,6 +613,18 @@ func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) } } + var amp *lnrpc.AMPRecord + if hop.AMP != nil { + rootShare := hop.AMP.RootShare() + setID := hop.AMP.SetID() + + amp = &lnrpc.AMPRecord{ + RootShare: rootShare[:], + SetId: setID[:], + ChildIndex: hop.AMP.ChildIndex(), + } + } + resp.Hops[i] = &lnrpc.Hop{ ChanId: hop.ChannelID, ChanCapacity: int64(chanCapacity), @@ -627,6 +639,7 @@ func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) CustomRecords: hop.CustomRecords, TlvPayload: !hop.LegacyPayload, MppRecord: mpp, + AmpRecord: amp, Metadata: hop.Metadata, EncryptedData: hop.EncryptedData, TotalAmtMsat: uint64(hop.TotalAmtMsat),