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 7d47f3c47..83ac747bb 100644 --- a/docs/release-notes/release-notes-0.18.0.md +++ b/docs/release-notes/release-notes-0.18.0.md @@ -73,6 +73,8 @@ a `shutdown` message if there were currently HTLCs on the channel. After this change, the shutdown procedure should be compliant with BOLT2 requirements. +* 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 @@ -281,6 +283,7 @@ * Amin Bashiri * Andras Banki-Horvath +* BitcoinerCoderBob * Carla Kirk-Cohen * Elle Mouton * ErikEk @@ -288,7 +291,9 @@ * Marcos Fernandez Perez * Matt Morehouse * Slyghtning +* Tee8z * Turtle * Ononiwu Maureen Chiamaka +* w3irdrobot * Yong Yu * Ziggie diff --git a/itest/lnd_amp_test.go b/itest/lnd_amp_test.go index e3b1898da..ba17a30b6 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 8da91aeed..420259de2 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),