Skip to content

Commit 1e1a856

Browse files
authored
Merge pull request #766 from ellemouton/tracing
accounts: address pendingPayments issues & add tracer
2 parents 04ef762 + 5e07588 commit 1e1a856

File tree

10 files changed

+1261
-94
lines changed

10 files changed

+1261
-94
lines changed

accounts/checkers.go

Lines changed: 234 additions & 36 deletions
Large diffs are not rendered by default.

accounts/checkers_test.go

Lines changed: 623 additions & 8 deletions
Large diffs are not rendered by default.

accounts/context.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package accounts
33
import (
44
"context"
55
"fmt"
6+
7+
"github.com/btcsuite/btclog"
8+
"github.com/lightningnetwork/lnd/build"
69
)
710

811
// ContextKey is the type that we use to identify account specific values in the
@@ -18,18 +21,23 @@ var (
1821
// KeyAccount is the key under which we store the account in the request
1922
// context.
2023
KeyAccount = ContextKey{"account"}
24+
25+
// KeyRequestID is the key under which we store the middleware request
26+
// ID.
27+
KeyRequestID = ContextKey{"request_id"}
2128
)
2229

2330
// FromContext tries to extract a value from the given context.
2431
func FromContext(ctx context.Context, key ContextKey) interface{} {
2532
return ctx.Value(key)
2633
}
2734

28-
// AddToContext adds the given value to the context for easy retrieval later on.
29-
func AddToContext(ctx context.Context, key ContextKey,
35+
// AddAccountToContext adds the given value to the context for easy retrieval
36+
// later on.
37+
func AddAccountToContext(ctx context.Context,
3038
value *OffChainBalanceAccount) context.Context {
3139

32-
return context.WithValue(ctx, key, value)
40+
return context.WithValue(ctx, KeyAccount, value)
3341
}
3442

3543
// AccountFromContext attempts to extract an account from the given context.
@@ -46,3 +54,46 @@ func AccountFromContext(ctx context.Context) (*OffChainBalanceAccount, error) {
4654

4755
return acct, nil
4856
}
57+
58+
// AddRequestIDToContext adds the given request ID to the context for easy
59+
// retrieval later on.
60+
func AddRequestIDToContext(ctx context.Context, value uint64) context.Context {
61+
return context.WithValue(ctx, KeyRequestID, value)
62+
}
63+
64+
// RequestIDFromContext attempts to extract a request ID from the given context.
65+
func RequestIDFromContext(ctx context.Context) (uint64, error) {
66+
val := FromContext(ctx, KeyRequestID)
67+
if val == nil {
68+
return 0, fmt.Errorf("no request ID found in context")
69+
}
70+
71+
reqID, ok := val.(uint64)
72+
if !ok {
73+
return 0, fmt.Errorf("invalid request ID value in context")
74+
}
75+
76+
return reqID, nil
77+
}
78+
79+
// requestScopedValuesFromCtx is a helper function that can be used to extract
80+
// an account and requestID from the given context. It also creates a new
81+
// prefixed logger that can be used by account request and response handlers.
82+
// Each log line will be prefixed by the account ID and the request ID.
83+
func requestScopedValuesFromCtx(ctx context.Context) (btclog.Logger,
84+
*OffChainBalanceAccount, uint64, error) {
85+
86+
acc, err := AccountFromContext(ctx)
87+
if err != nil {
88+
return nil, nil, 0, err
89+
}
90+
91+
reqID, err := RequestIDFromContext(ctx)
92+
if err != nil {
93+
return nil, nil, 0, err
94+
}
95+
96+
prefix := fmt.Sprintf("[account: %s, request: %d]", acc.ID, reqID)
97+
98+
return build.NewPrefixLog(prefix, log), acc, reqID, nil
99+
}

accounts/interceptor.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,10 @@ func (s *InterceptorService) Intercept(ctx context.Context,
101101
)
102102
}
103103

104-
// We now add the account to the incoming context to give each checker
105-
// access to it if required.
106-
ctxAccount := AddToContext(ctx, KeyAccount, acct)
104+
// We now add the account and request ID to the incoming context to give
105+
// each checker access to them if required.
106+
ctx = AddAccountToContext(ctx, acct)
107+
ctx = AddRequestIDToContext(ctx, req.RequestId)
107108

108109
switch r := req.InterceptType.(type) {
109110
// In the authentication phase we just check that the account hasn't
@@ -120,18 +121,42 @@ func (s *InterceptorService) Intercept(ctx context.Context,
120121
}
121122

122123
return mid.RPCErr(req, s.checkers.checkIncomingRequest(
123-
ctxAccount, r.Request.MethodFullUri, msg,
124+
ctx, r.Request.MethodFullUri, msg,
124125
))
125126

126127
// Parse and possibly manipulate outgoing responses.
127128
case *lnrpc.RPCMiddlewareRequest_Response:
129+
if r.Response.IsError {
130+
parsedErr := mid.ParseResponseErr(r.Response.Serialized)
131+
132+
replacementErr, err := s.checkers.handleErrorResponse(
133+
ctx, r.Response.MethodFullUri, parsedErr,
134+
)
135+
if err != nil {
136+
return mid.RPCErr(req, err)
137+
}
138+
139+
// No error occurred but the response error should be
140+
// replaced with the given custom error. Wrap it in the
141+
// correct RPC response of the interceptor now.
142+
if replacementErr != nil {
143+
return mid.RPCErrReplacement(
144+
req, replacementErr,
145+
)
146+
}
147+
148+
// No error and no replacement, just return an empty
149+
// response of the correct type.
150+
return mid.RPCOk(req)
151+
}
152+
128153
msg, err := parseRPCMessage(r.Response)
129154
if err != nil {
130155
return mid.RPCErr(req, err)
131156
}
132157

133158
replacement, err := s.checkers.replaceOutgoingResponse(
134-
ctxAccount, r.Response.MethodFullUri, msg,
159+
ctx, r.Response.MethodFullUri, msg,
135160
)
136161
if err != nil {
137162
return mid.RPCErr(req, err)

accounts/interface.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ func ParseAccountID(idStr string) (*AccountID, error) {
5353
return &id, nil
5454
}
5555

56+
// String returns the string representation of the AccountID.
57+
func (a AccountID) String() string {
58+
return hex.EncodeToString(a[:])
59+
}
60+
5661
// PaymentEntry is the data we track per payment that is associated with an
5762
// account. This basically includes all information required to make sure
5863
// in-flight payments don't exceed the total available account balance.
@@ -252,4 +257,38 @@ type Service interface {
252257
// restarted.
253258
AssociatePayment(id AccountID, paymentHash lntypes.Hash,
254259
fullAmt lnwire.MilliSatoshi) error
260+
261+
// PaymentErrored removes a pending payment from the accounts
262+
// registered payment list. This should only ever be called if we are
263+
// sure that the payment request errored out.
264+
PaymentErrored(id AccountID, hash lntypes.Hash) error
265+
266+
RequestValuesStore
267+
}
268+
269+
// RequestValues holds various values associated with a specific request that
270+
// we may want access to when handling the response. At the moment this only
271+
// stores payment related data.
272+
type RequestValues struct {
273+
// PaymentHash is the hash of the payment that this request is
274+
// associated with.
275+
PaymentHash lntypes.Hash
276+
277+
// PaymentAmount is the value of the payment being made.
278+
PaymentAmount lnwire.MilliSatoshi
279+
}
280+
281+
// RequestValuesStore is a store that can be used to keep track of the mapping
282+
// between a request ID and various values associated with that request which
283+
// we may want access to when handling the request response.
284+
type RequestValuesStore interface {
285+
// RegisterValues stores values for the given request ID.
286+
RegisterValues(reqID uint64, values *RequestValues) error
287+
288+
// GetValues returns the corresponding request values for the given
289+
// request ID if they exist.
290+
GetValues(reqID uint64) (*RequestValues, bool)
291+
292+
// DeleteValues deletes any values stored for the given request ID.
293+
DeleteValues(reqID uint64)
255294
}

accounts/log.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"github.com/lightningnetwork/lnd/build"
66
)
77

8-
const Subsystem = "ACCT"
8+
const Subsystem = "ACNT"
99

1010
// log is a logger that is initialized with no output filters. This
1111
// means the package will not perform any logging by default until the caller

0 commit comments

Comments
 (0)