From 29d82c84a4fb93252d7b038fef012edaf89fbf0a Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 27 Dec 2024 14:20:29 -0500 Subject: [PATCH] Mark successful payjoin sessions in storage Payjoin sessions marked 'complete' do not get spawned. This reduces the number of isolates spawned on resume or restart. Mark rather than delete so that the historic status may eventually be shown in transaction history. --- lib/_pkg/payjoin/manager.dart | 44 +++++++++++++++++++++++++++----- lib/_pkg/payjoin/storage.dart | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/lib/_pkg/payjoin/manager.dart b/lib/_pkg/payjoin/manager.dart index 82ac625e..1a5c1cec 100644 --- a/lib/_pkg/payjoin/manager.dart +++ b/lib/_pkg/payjoin/manager.dart @@ -113,12 +113,14 @@ class PayjoinManager { completer.complete(err); return; } + // Successfully sent payjoin PayjoinEventBus().emit( PayjoinBroadcastEvent( txid: wtxid!.$2, ), ); await _cleanupSession(pjUri); + await _payjoinStorage.markSenderSessionComplete(pjUri); completer.complete(null); } } else if (message is Err) { @@ -244,6 +246,7 @@ class PayjoinManager { }); case 'proposal_sent': await _cleanupSession(receiver.id()); + await _payjoinStorage.markSenderSessionComplete(receiver.id()); completer.complete(null); } } catch (e) { @@ -295,10 +298,13 @@ class PayjoinManager { if (senderErr != null) throw senderErr; final filteredReceivers = receiverSessions - .where((session) => session.walletId == wallet.id) + .where((session) => + session.walletId == wallet.id && + session.status != PayjoinSessionStatus.success) .toList(); final filteredSenders = senderSessions.where((session) { - return session.walletId == wallet.id; + return session.walletId == wallet.id && + session.status != PayjoinSessionStatus.success; }).toList(); final spawnedReceivers = filteredReceivers.map((session) { @@ -359,8 +365,19 @@ class PayjoinManager { } } +enum PayjoinSessionStatus { + pending, + success, +} + class SendSession { - SendSession(this._isTestnet, this._sender, this._walletId, this._pjUri); + SendSession( + this._isTestnet, + this._sender, + this._walletId, + this._pjUri, + this._status, + ); // Deserialize JSON to Receiver factory SendSession.fromJson(Map json) { @@ -369,6 +386,9 @@ class SendSession { Sender.fromJson(json['sender'] as String), json['walletId'] as String, json['pjUri'] as String, + json['status'] != null + ? PayjoinSessionStatus.values.byName(json['status'] as String) + : null, ); } @@ -376,12 +396,12 @@ class SendSession { final Sender _sender; final String _walletId; final String _pjUri; - + final PayjoinSessionStatus? _status; bool get isTestnet => _isTestnet; Sender get sender => _sender; String get walletId => _walletId; String get pjUri => _pjUri; - + PayjoinSessionStatus? get status => _status; // Serialize Receiver to JSON Map toJson() { return { @@ -389,34 +409,46 @@ class SendSession { 'sender': _sender.toJson(), 'walletId': _walletId, 'pjUri': _pjUri, + 'status': _status?.name, }; } } class RecvSession { - RecvSession(this._isTestnet, this._receiver, this._walletId); + RecvSession( + this._isTestnet, + this._receiver, + this._walletId, + this._status, + ); factory RecvSession.fromJson(Map json) { return RecvSession( json['isTestnet'] as bool, Receiver.fromJson(json['receiver'] as String), json['walletId'] as String, + json['status'] != null + ? PayjoinSessionStatus.values.byName(json['status'] as String) + : null, ); } final bool _isTestnet; final Receiver _receiver; final String _walletId; + final PayjoinSessionStatus? _status; bool get isTestnet => _isTestnet; Receiver get receiver => _receiver; String get walletId => _walletId; + PayjoinSessionStatus? get status => _status; Map toJson() { return { 'isTestnet': isTestnet, 'receiver': receiver.toJson(), 'walletId': walletId, + 'status': _status?.name, }; } } diff --git a/lib/_pkg/payjoin/storage.dart b/lib/_pkg/payjoin/storage.dart index 6f2c4afe..e7a7d299 100644 --- a/lib/_pkg/payjoin/storage.dart +++ b/lib/_pkg/payjoin/storage.dart @@ -42,6 +42,7 @@ class PayjoinStorage { isTestnet, receiver, walletId, + PayjoinSessionStatus.pending, ); await _hiveStorage.saveValue( @@ -73,6 +74,28 @@ class PayjoinStorage { } } + Future markReceiverSessionComplete(String sessionId) async { + try { + final (session, err) = await readReceiverSession(sessionId); + if (err != null) return err; + + final updatedSession = RecvSession( + session!.isTestnet, + session.receiver, + session.walletId, + PayjoinSessionStatus.success, + ); + + await _hiveStorage.saveValue( + key: receiverPrefix + sessionId, + value: jsonEncode(updatedSession.toJson()), + ); + return null; + } catch (e) { + return Err(e.toString()); + } + } + Future<(List, Err?)> readAllReceivers() async { //deleteAllSessions(); try { @@ -109,6 +132,7 @@ class PayjoinStorage { sender, walletId, pjUrl, + PayjoinSessionStatus.pending, ); await _hiveStorage.saveValue( @@ -139,6 +163,29 @@ class PayjoinStorage { } } + Future markSenderSessionComplete(String pjUrl) async { + try { + final (session, err) = await readSenderSession(pjUrl); + if (err != null) return err; + + final updatedSession = SendSession( + session!.isTestnet, + session.sender, + session.walletId, + session.pjUri, + PayjoinSessionStatus.success, + ); + + await _hiveStorage.saveValue( + key: senderPrefix + pjUrl, + value: jsonEncode(updatedSession.toJson()), + ); + return null; + } catch (e) { + return Err(e.toString()); + } + } + Future<(List, Err?)> readAllSenders() async { try { final (allData, err) = await _hiveStorage.getAll();