processLineageCredit processes a credit transaction for fund lineage tracking. It creates shadow balances and queues a shadow transaction to track the provider's funds. Parameters: - ctx context.Context: The context for the operation. - txn *model.Transaction: The credit transaction being processed
(ctx context.Context, txn *model.Transaction, destBalance *model.Balance, provider string)
| 235 | // Returns: |
| 236 | // - error: An error if the credit processing fails. |
| 237 | func (l *LedgerForge) processLineageCredit(ctx context.Context, txn *model.Transaction, destBalance *model.Balance, provider string) error { |
| 238 | ctx, span := tracer.Start(ctx, "ProcessLineageCredit") |
| 239 | defer span.End() |
| 240 | |
| 241 | identityID := destBalance.IdentityID |
| 242 | if identityID == "" { |
| 243 | return fmt.Errorf("destination balance %s has no identity_id for lineage tracking", destBalance.BalanceID) |
| 244 | } |
| 245 | |
| 246 | // Get or create the shadow and aggregate balances first (before locking) |
| 247 | shadowBalance, aggregateBalance, err := l.getOrCreateLineageBalances(ctx, identityID, provider, txn.Currency) |
| 248 | if err != nil { |
| 249 | return err |
| 250 | } |
| 251 | |
| 252 | // Use MultiLocker to lock both shadow and aggregate balances |
| 253 | locker, err := l.acquireLineageLocks(ctx, []string{shadowBalance.BalanceID, aggregateBalance.BalanceID}) |
| 254 | if err != nil { |
| 255 | span.RecordError(err) |
| 256 | return err |
| 257 | } |
| 258 | defer l.releaseLock(ctx, locker) |
| 259 | |
| 260 | if err := l.queueShadowCreditTransaction(ctx, txn, destBalance, provider, shadowBalance, aggregateBalance, identityID); err != nil { |
| 261 | return err |
| 262 | } |
| 263 | |
| 264 | if err := l.upsertCreditLineageMapping(ctx, destBalance, provider, shadowBalance, aggregateBalance, identityID); err != nil { |
| 265 | logrus.Errorf("failed to create lineage mapping after shadow transaction: %v (txn: %s, provider: %s)", err, txn.TransactionID, provider) |
| 266 | span.RecordError(err) |
| 267 | // Don't return error - shadow transaction succeeded, mapping is for optimization |
| 268 | } |
| 269 | |
| 270 | span.AddEvent("Lineage credit processed", trace.WithAttributes( |
| 271 | attribute.String("provider", provider), |
| 272 | attribute.String("shadow_balance", shadowBalance.BalanceID), |
| 273 | )) |
| 274 | return nil |
| 275 | } |
| 276 | |
| 277 | // getOrCreateLineageBalances retrieves or creates the shadow and aggregate balances for lineage tracking. |
| 278 | // |
no test coverage detected