Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include outgoing payment description in audit memo #182

Merged
merged 1 commit into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions accounting/entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,18 @@ func paymentReference(sequenceNumber uint64, preimage lntypes.Preimage) string {

// paymentNote creates a note for payments from our node.
// nolint: interfacer
func paymentNote(dest *route.Vertex) string {
if dest == nil {
return ""
func paymentNote(dest *route.Vertex, memo *string) string {
var notes []string

if memo != nil && *memo != "" {
notes = append(notes, fmt.Sprintf("memo: %v", *memo))
}
return dest.String()

if dest != nil {
notes = append(notes, fmt.Sprintf("destination: %v", dest))
}

return strings.Join(notes, "/")
}

// paymentEntry creates an entry for an off chain payment, including fee entries
Expand All @@ -432,7 +439,7 @@ func paymentEntry(payment paymentInfo, paidToSelf bool,

// Create a note for our payment. Since we have already checked that our
// payment is settled, we will not have a nil preimage.
note := paymentNote(payment.destination)
note := paymentNote(payment.destination, payment.description)
ref := paymentReference(payment.SequenceNumber, *payment.Preimage)

// Payment values are expressed as positive values over rpc, but they
Expand Down
12 changes: 5 additions & 7 deletions accounting/entries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@ var (
Tx: &wire.MsgTx{},
}

paymentRequest = "lnbcrt10n1p0t6nmypp547evsfyrakg0nmyw59ud9cegkt99yccn5nnp4suq3ac4qyzzgevsdqqcqzpgsp54hvffpajcyddm20k3ptu53930425hpnv8m06nh5jrd6qhq53anrq9qy9qsqphhzyenspf7kfwvm3wyu04fa8cjkmvndyexlnrmh52huwa4tntppjmak703gfln76rvswmsx2cz3utsypzfx40dltesy8nj64ttgemgqtwfnj9"

invoiceMemo = "memo"

invoiceAmt = lnwire.MilliSatoshi(300)

invoiceOverpaidAmt = lnwire.MilliSatoshi(400)
Expand All @@ -112,7 +108,7 @@ var (

paymentTime = time.Unix(1590399649, 0)

paymentHash = "11f414479f0a0c2762492c71c58dded5dce99d56d65c3fa523f73513605bebb3"
paymentHash = "0001020304050607080900010203040506070809000102030405060708090102"
pmtHash, _ = lntypes.MakeHashFromStr(paymentHash)

paymentPreimage = "adfef20b24152accd4ed9a05257fb77203d90a8bbbe6d4069a75c5320f0538d9"
Expand All @@ -134,11 +130,13 @@ var (
Fee: lnwire.MilliSatoshi(paymentFeeMsat),
Htlcs: []*lnrpc.HTLCAttempt{{}},
SequenceNumber: uint64(paymentIndex),
PaymentRequest: paymentRequest,
}

payInfo = paymentInfo{
Payment: payment,
destination: &otherPubkey,
description: &invoiceMemo,
settleTime: paymentTime,
}

Expand Down Expand Up @@ -758,7 +756,7 @@ func TestPaymentEntry(t *testing.T) {
FiatValue: fiat.MsatToFiat(mockBTCPrice.Price, amtMsat),
TxID: paymentHash,
Reference: paymentRef,
Note: paymentNote(&otherPubkey),
Note: paymentNote(&otherPubkey, &invoiceMemo),
Type: EntryTypePayment,
OnChain: false,
Credit: false,
Expand All @@ -773,7 +771,7 @@ func TestPaymentEntry(t *testing.T) {
FiatValue: fiat.MsatToFiat(mockBTCPrice.Price, feeMsat),
TxID: paymentHash,
Reference: FeeReference(paymentRef),
Note: paymentNote(&otherPubkey),
Note: paymentNote(&otherPubkey, &invoiceMemo),
Type: EntryTypeFee,
OnChain: false,
Credit: false,
Expand Down
58 changes: 34 additions & 24 deletions accounting/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,16 @@ func filterInvoices(startTime, endTime time.Time,
return filtered
}

// paymentInfo wraps a lndclient payment struct with a destination, if it is
// available from the information we have available, and its settle time.
// Since we now allow multi-path payments, a single payment may have multiple
// htlcs resolved over a period of time. We use the most recent settle time for
// payment because payments are not considered settled until all the htlcs are
// resolved.
// paymentInfo wraps a lndclient payment struct with a destination, and
// description if available from the information we have available, and its
// settle time. Since we now allow multi-path payments, a single payment may
// have multiple htlcs resolved over a period of time. We use the most recent
// settle time for payment because payments are not considered settled until
// all the htlcs are resolved.
type paymentInfo struct {
lndclient.Payment
destination *route.Vertex
description *string
settleTime time.Time
}

Expand All @@ -135,24 +136,31 @@ func preProcessPayments(payments []lndclient.Payment,
paymentList := make([]paymentInfo, len(payments))

for i, payment := range payments {
// Try to get our payment destination from our set of htlcs.
// If we cannot get it from our htlcs (which is the case for
// legacy payments that did not store htlcs), we try to get it
// from our payment request. This value may not be present for
// all payments, so we do not error if it is not.
// Attempt to obtain the payment destination and description
// from our payment request. If this is not possible (which
// can be the case for legacy payments that did not store
// payment requests, or payments that pay directly to a
// payment hash), then try to get it from our HTLCs. Note
// that HTLCs may also not be available for legacy payments
// that did not store HTLCs. In the event that we get a
// destination from both sources, we prefer the destination
// from the HTLCs.
payReqDestination, description, err := paymentRequestDetails(
payment.PaymentRequest, decode,
)
if err != nil && err != errNoPaymentRequest {
return nil, err
}

destination, err := paymentHtlcDestination(payment)
if err != nil {
destination, err = paymentRequestDestination(
payment.PaymentRequest, decode,
)
if err != nil && err != errNoPaymentRequest {
return nil, err
}
destination = payReqDestination
}

pmt := paymentInfo{
Payment: payment,
destination: destination,
description: description,
}

// If the payment did not succeed, we can add it to our list
Expand Down Expand Up @@ -212,21 +220,23 @@ func paymentHtlcDestination(payment lndclient.Payment) (*route.Vertex, error) {
return &lastHopPubkey, nil
}

// paymentRequestDestination attempts to decode a payment address, and returns
// the destination.
func paymentRequestDestination(paymentRequest string,
decode decodePaymentRequest) (*route.Vertex, error) {
// paymentRequestDetails attempts to decode a payment address, and returns
// the destination and the description.
func paymentRequestDetails(paymentRequest string,
decode decodePaymentRequest) (*route.Vertex, *string, error) {

if paymentRequest == "" {
return nil, errNoPaymentRequest
return nil, nil, errNoPaymentRequest
}

payReq, err := decode(paymentRequest)
if err != nil {
return nil, fmt.Errorf("decode payment request failed: %w", err)
return nil, nil, fmt.Errorf(
"decode payment request failed: %w", err,
)
}

return &payReq.Destination, nil
return &payReq.Destination, &payReq.Description, nil
}

// filterPayments filters out unsuccessful payments and those which did not
Expand Down
23 changes: 15 additions & 8 deletions accounting/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ func decode(toSelf bool) func(_ string) (*lndclient.PaymentRequest,

return &lndclient.PaymentRequest{
Destination: pubkey,
Description: invoiceMemo,
}, nil
}
}
Expand Down Expand Up @@ -437,35 +438,39 @@ func TestPaymentHtlcDestination(t *testing.T) {
}
}

// TestPaymentRequestDestination tests getting of payment destinations from our
// TestPaymentRequestDestination tests getting of payment details from our
// payment request.
func TestPaymentRequestDestination(t *testing.T) {
func TestPaymentRequestDetails(t *testing.T) {
tests := []struct {
name string
paymentRequest string
decode decodePaymentRequest
dest *route.Vertex
destination *route.Vertex
description *string
err error
}{
{
name: "no payment request",
decode: decode(true),
paymentRequest: "",
dest: nil,
destination: nil,
description: nil,
err: errNoPaymentRequest,
},
{
name: "to self",
decode: decode(true),
paymentRequest: paymentRequest,
dest: &ourPubKey,
destination: &ourPubKey,
description: &invoiceMemo,
err: nil,
},
{
name: "not to self",
decode: decode(false),
paymentRequest: paymentRequest,
dest: &otherPubkey,
destination: &otherPubkey,
description: &invoiceMemo,
err: nil,
},
}
Expand All @@ -476,11 +481,13 @@ func TestPaymentRequestDestination(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

dest, err := paymentRequestDestination(
destination, description, err := paymentRequestDetails(
test.paymentRequest, test.decode,
)

require.Equal(t, test.err, err)
require.Equal(t, test.dest, dest)
require.Equal(t, test.destination, destination)
require.Equal(t, test.description, description)
})
}
}
3 changes: 3 additions & 0 deletions accounting/off_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var (
paymentHash2 = "a5530c5930b9eb7ea4284bcff39da52c6bca3103fc790749eb632911edc7143b"
hash2, _ = lntypes.MakeHashFromStr(paymentHash2)

paymentRequest = "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp"
invoiceMemo = "1 cup coffee"

hopToUs = &lnrpc.Hop{
PubKey: ourPK,
}
Expand Down
Loading