Fix Bitcoin transactions not showing (#978)
* handle multiple responses coming in a single event * Add timeout for getting transaction info, to allow other transactions to be returned in case of any failure or network issue * Handle other cases of receiving multiple messages in the same response
Omar Hatem committed
Jul 13, 2023 at 21:46 UTC
bc432b104228c76f785563a903775d72403c17d6
1 file changed
+51
-37
cw_bitcoin/lib/electrum.dart
+51
-37
@@ -66,54 +66,68 @@ class ElectrumClient {
66
socket!.listen((Uint8List event) {
67
try {
68
final msg = utf8.decode(event.toList());
69
- final response =
70
- json.decode(msg) as Map<String, dynamic>;
71
- _handleResponse(response);
72
- } on FormatException catch (e) {
73
- final msg = e.message.toLowerCase();
74
-
75
- if (e.source is String) {
76
- unterminatedString += e.source as String;
77
- }
78
-
79
- if (msg.contains("not a subtype of type")) {
80
- unterminatedString += e.source as String;
81
- return;
82
- }
83
-
84
- if (isJSONStringCorrect(unterminatedString)) {
85
- final response =
86
- json.decode(unterminatedString) as Map<String, dynamic>;
87
- _handleResponse(response);
88
- unterminatedString = '';
89
- }
90
- } on TypeError catch (e) {
91
- if (!e.toString().contains('Map<String, Object>') && !e.toString().contains('Map<String, dynamic>')) {
92
- return;
93
- }
94
-
95
- final source = utf8.decode(event.toList());
96
- unterminatedString += source;
97
-
98
- if (isJSONStringCorrect(unterminatedString)) {
99
- final response =
100
- json.decode(unterminatedString) as Map<String, dynamic>;
101
- _handleResponse(response);
102
- // unterminatedString = null;
103
- unterminatedString = '';
69
+ final messagesList = msg.split("\n");
70
+ for (var message in messagesList) {
71
+ if (message.isEmpty) {
72
+ continue;
73
+ }
74
+ _parseResponse(message);
75
}
76
} catch (e) {
77
print(e.toString());
78
}
79
}, onError: (Object error) {
80
print(error.toString());
81
+ unterminatedString = '';
82
_setIsConnected(false);
83
}, onDone: () {
84
+ unterminatedString = '';
85
_setIsConnected(false);
86
});
87
keepAlive();
88
}
89
90
+ void _parseResponse(String message) {
91
+ try {
92
+ final response = json.decode(message) as Map<String, dynamic>;
93
+ _handleResponse(response);
94
+ } on FormatException catch (e) {
95
+ final msg = e.message.toLowerCase();
96
+
97
+ if (e.source is String) {
98
+ unterminatedString += e.source as String;
99
+ }
100
+
101
+ if (msg.contains("not a subtype of type")) {
102
+ unterminatedString += e.source as String;
103
+ return;
104
+ }
105
+
106
+ if (isJSONStringCorrect(unterminatedString)) {
107
+ final response =
108
+ json.decode(unterminatedString) as Map<String, dynamic>;
109
+ _handleResponse(response);
110
+ unterminatedString = '';
111
+ }
112
+ } on TypeError catch (e) {
113
+ if (!e.toString().contains('Map<String, Object>') && !e.toString().contains('Map<String, dynamic>')) {
114
+ return;
115
+ }
116
+
117
+ unterminatedString += message;
118
+
119
+ if (isJSONStringCorrect(unterminatedString)) {
120
+ final response =
121
+ json.decode(unterminatedString) as Map<String, dynamic>;
122
+ _handleResponse(response);
123
+ // unterminatedString = null;
124
+ unterminatedString = '';
125
+ }
126
+ } catch (e) {
127
+ print(e.toString());
128
+ }
129
+ }
130
+
131
void keepAlive() {
132
_aliveTimer?.cancel();
133
_aliveTimer = Timer.periodic(aliveTimerDuration, (_) async => ping());
@@ -217,7 +231,7 @@ class ElectrumClient {
231
232
Future<Map<String, dynamic>> getTransactionRaw(
233
{required String hash}) async =>
220
- call(method: 'blockchain.transaction.get', params: [hash, true])
234
+ callWithTimeout(method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000)
235
.then((dynamic result) {
236
if (result is Map<String, dynamic>) {
237
return result;
@@ -228,7 +242,7 @@ class ElectrumClient {
242
243
Future<String> getTransactionHex(
244
{required String hash}) async =>
231
- call(method: 'blockchain.transaction.get', params: [hash, false])
245
+ callWithTimeout(method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000)
246
.then((dynamic result) {
247
if (result is String) {
248
return result;