mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39:51 +00:00
fix: batch limit exceeded errors [skip ci]
This commit is contained in:
parent
2afad62c0c
commit
c74227ee36
3 changed files with 137 additions and 74 deletions
|
@ -1225,20 +1225,12 @@ abstract class ElectrumWalletBase<T extends ElectrumWalletAddresses>
|
|||
}
|
||||
|
||||
@action
|
||||
Future<void> onScripthashesStatusResponse(Map<String, dynamic>? result) async {
|
||||
if (result != null) {
|
||||
for (final entry in result.entries) {
|
||||
final address = entry.key;
|
||||
|
||||
final scripthash = walletAddresses.allAddresses
|
||||
.firstWhereOrNull((element) => element.address == address)
|
||||
?.scriptHash;
|
||||
|
||||
if (scripthash != null) {
|
||||
scripthashesWithStatus.add(scripthash);
|
||||
}
|
||||
}
|
||||
Future<void> onScripthashesStatusResponse(ElectrumWorkerScripthashesResponse result) async {
|
||||
if (result.status == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
scripthashesWithStatus.add(result.scripthash);
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -1653,20 +1645,24 @@ abstract class ElectrumWalletBase<T extends ElectrumWalletAddresses>
|
|||
@action
|
||||
Future<void> subscribeForStatuses([bool? wait]) async {
|
||||
Map<String, String> scripthashByAddress = {};
|
||||
Map<String, String> addressByScripthashes = {};
|
||||
walletAddresses.allAddresses.forEach((addressRecord) {
|
||||
scripthashByAddress[addressRecord.address] = addressRecord.scriptHash;
|
||||
addressByScripthashes[addressRecord.scriptHash] = addressRecord.address;
|
||||
});
|
||||
|
||||
if (wait == true) {
|
||||
await waitSendWorker(
|
||||
ElectrumWorkerScripthashesSubscribeRequest(
|
||||
scripthashByAddress: scripthashByAddress,
|
||||
addressByScripthashes: addressByScripthashes,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
workerSendPort!.send(
|
||||
ElectrumWorkerScripthashesSubscribeRequest(
|
||||
scripthashByAddress: scripthashByAddress,
|
||||
addressByScripthashes: addressByScripthashes,
|
||||
).toJson(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -212,8 +212,6 @@ class ElectrumWorker {
|
|||
if (tx.confirmations != newConfirmationsValue) {
|
||||
tx.confirmations = newConfirmationsValue;
|
||||
tx.isPending = tx.confirmations == 0;
|
||||
if (!anyTxWasUpdated) {
|
||||
}
|
||||
anyTxWasUpdated = true;
|
||||
}
|
||||
}
|
||||
|
@ -233,61 +231,93 @@ class ElectrumWorker {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> _handleBatchScriphashesSubscribe(
|
||||
ElectrumWorkerScripthashesSubscribeRequest request, [
|
||||
int chunkSize = 100,
|
||||
List<String>? allScriptHashes,
|
||||
]) async {
|
||||
final scripthashByAddress = request.scripthashByAddress;
|
||||
allScriptHashes ??= scripthashByAddress.values.toList();
|
||||
|
||||
final chunks = allScriptHashes.sublist(
|
||||
0,
|
||||
chunkSize > allScriptHashes.length ? allScriptHashes.length : chunkSize,
|
||||
);
|
||||
|
||||
final req = ElectrumBatchRequestScriptHashSubscribe(scriptHashes: chunks);
|
||||
final batchStreams = await _electrumClient!.batchSubscribe(req);
|
||||
|
||||
if (batchStreams != null) {
|
||||
int i = 0;
|
||||
|
||||
for (final stream in batchStreams) {
|
||||
stream.subscription.listen((status) async {
|
||||
final batch = req.onResponse(status, stream.params);
|
||||
// https://electrumx.readthedocs.io/en/latest/protocol-basics.html#status
|
||||
// The status of the script hash is the hash of the tx history, or null if the string is empty because there are no transactions
|
||||
final result = batch.result;
|
||||
|
||||
final scriptHash = batch.paramForRequest!.first as String;
|
||||
final address = request.addressByScripthashes[scriptHash]!;
|
||||
|
||||
if (result != null) {
|
||||
_sendResponse(
|
||||
ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: ElectrumWorkerScripthashesResponse(
|
||||
address: address,
|
||||
scripthash: scriptHash,
|
||||
status: result,
|
||||
),
|
||||
id: request.id,
|
||||
completed: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
scripthashByAddress.remove(address);
|
||||
|
||||
await _electrumClient!.request(
|
||||
ElectrumRequestScriptHashUnSubscribe(scriptHash: scriptHash),
|
||||
);
|
||||
|
||||
i++;
|
||||
|
||||
if (i == chunkSize) {
|
||||
_handleBatchScriphashesSubscribe(
|
||||
request,
|
||||
chunkSize,
|
||||
scripthashByAddress.values.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
// Got all batches, complete
|
||||
if (i == chunks.length && scripthashByAddress.isEmpty) {
|
||||
_sendResponse(
|
||||
ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: ElectrumWorkerScripthashesResponse(
|
||||
address: address,
|
||||
scripthash: scriptHash,
|
||||
status: null,
|
||||
),
|
||||
id: request.id,
|
||||
completed: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
}, onError: (Object e) {
|
||||
// print(e);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_serverCapability!.supportsBatching = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleScriphashesSubscribe(
|
||||
ElectrumWorkerScripthashesSubscribeRequest request,
|
||||
) async {
|
||||
if (_serverCapability!.supportsBatching) {
|
||||
try {
|
||||
final req = ElectrumBatchRequestScriptHashSubscribe(
|
||||
scriptHashes: request.scripthashByAddress.values.toList() as List<String>,
|
||||
);
|
||||
|
||||
final streams = await _electrumClient!.batchSubscribe(req);
|
||||
|
||||
if (streams != null) {
|
||||
int i = 0;
|
||||
|
||||
await Future.wait(streams.map((stream) async {
|
||||
stream.subscription.listen((status) {
|
||||
final batch = req.onResponse(status, stream.params);
|
||||
final result = batch.result;
|
||||
|
||||
final scriptHash = batch.paramForRequest!.first as String;
|
||||
final address = request.scripthashByAddress.entries
|
||||
.firstWhere(
|
||||
(entry) => entry.value == scriptHash,
|
||||
)
|
||||
.key;
|
||||
|
||||
if (result != null) {
|
||||
_sendResponse(
|
||||
ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: {address: result},
|
||||
id: request.id,
|
||||
completed: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (i == request.scripthashByAddress.length) {
|
||||
_sendResponse(ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: {address: null},
|
||||
id: request.id,
|
||||
completed: true,
|
||||
));
|
||||
}
|
||||
}, onError: () {
|
||||
_serverCapability!.supportsBatching = false;
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
_serverCapability!.supportsBatching = false;
|
||||
}
|
||||
} catch (_) {
|
||||
_serverCapability!.supportsBatching = false;
|
||||
}
|
||||
_handleBatchScriphashesSubscribe(request);
|
||||
}
|
||||
|
||||
if (_serverCapability!.supportsBatching == false) {
|
||||
|
@ -310,16 +340,25 @@ class ElectrumWorker {
|
|||
stream.listen((status) async {
|
||||
if (status != null) {
|
||||
_sendResponse(ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: {address: req.onResponse(status)},
|
||||
result: ElectrumWorkerScripthashesResponse(
|
||||
address: address,
|
||||
scripthash: scripthash,
|
||||
status: req.onResponse(status),
|
||||
),
|
||||
id: request.id,
|
||||
completed: false,
|
||||
));
|
||||
}
|
||||
i++;
|
||||
|
||||
// Got all statuses, complete
|
||||
if (i == request.scripthashByAddress.length) {
|
||||
_sendResponse(ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: {address: null},
|
||||
result: ElectrumWorkerScripthashesResponse(
|
||||
address: address,
|
||||
scripthash: scripthash,
|
||||
status: null,
|
||||
),
|
||||
id: request.id,
|
||||
completed: true,
|
||||
));
|
||||
|
|
|
@ -3,11 +3,13 @@ part of 'methods.dart';
|
|||
class ElectrumWorkerScripthashesSubscribeRequest implements ElectrumWorkerRequest {
|
||||
ElectrumWorkerScripthashesSubscribeRequest({
|
||||
required this.scripthashByAddress,
|
||||
required this.addressByScripthashes,
|
||||
this.id,
|
||||
this.completed = false,
|
||||
});
|
||||
|
||||
final Map<String, dynamic> scripthashByAddress;
|
||||
final Map<String, String> scripthashByAddress;
|
||||
final Map<String, String> addressByScripthashes;
|
||||
final int? id;
|
||||
final bool completed;
|
||||
|
||||
|
@ -17,7 +19,8 @@ class ElectrumWorkerScripthashesSubscribeRequest implements ElectrumWorkerReques
|
|||
@override
|
||||
factory ElectrumWorkerScripthashesSubscribeRequest.fromJson(Map<dynamic, dynamic> json) {
|
||||
return ElectrumWorkerScripthashesSubscribeRequest(
|
||||
scripthashByAddress: json['scripthashes'] as Map<String, String>,
|
||||
scripthashByAddress: json['scripthashByAddress'] as Map<String, String>,
|
||||
addressByScripthashes: json['addressByScripthashes'] as Map<String, String>,
|
||||
id: json['id'] as int?,
|
||||
completed: json['completed'] as bool? ?? false,
|
||||
);
|
||||
|
@ -29,7 +32,8 @@ class ElectrumWorkerScripthashesSubscribeRequest implements ElectrumWorkerReques
|
|||
'method': method,
|
||||
'id': id,
|
||||
'completed': completed,
|
||||
'scripthashes': scripthashByAddress,
|
||||
'scripthashByAddress': scripthashByAddress,
|
||||
'addressByScripthashes': addressByScripthashes,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +48,32 @@ class ElectrumWorkerScripthashesSubscribeError extends ElectrumWorkerErrorRespon
|
|||
final String method = ElectrumRequestMethods.scriptHashSubscribe.method;
|
||||
}
|
||||
|
||||
class ElectrumWorkerScripthashesResponse {
|
||||
ElectrumWorkerScripthashesResponse({
|
||||
required this.address,
|
||||
required this.scripthash,
|
||||
this.status,
|
||||
});
|
||||
|
||||
final String address;
|
||||
final String scripthash;
|
||||
final String? status;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'address': address, 'scripthash': scripthash, 'status': status};
|
||||
}
|
||||
|
||||
static ElectrumWorkerScripthashesResponse fromJson(Map<String, dynamic> json) {
|
||||
return ElectrumWorkerScripthashesResponse(
|
||||
address: json['address'] as String,
|
||||
scripthash: json['scripthash'] as String,
|
||||
status: json['status'] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ElectrumWorkerScripthashesSubscribeResponse
|
||||
extends ElectrumWorkerResponse<Map<String, dynamic>?, Map<String, dynamic>?> {
|
||||
extends ElectrumWorkerResponse<ElectrumWorkerScripthashesResponse, Map<String, dynamic>?> {
|
||||
ElectrumWorkerScripthashesSubscribeResponse({
|
||||
required super.result,
|
||||
super.error,
|
||||
|
@ -55,13 +83,13 @@ class ElectrumWorkerScripthashesSubscribeResponse
|
|||
|
||||
@override
|
||||
Map<String, dynamic>? resultJson(result) {
|
||||
return result;
|
||||
return result.toJson();
|
||||
}
|
||||
|
||||
@override
|
||||
factory ElectrumWorkerScripthashesSubscribeResponse.fromJson(Map<String, dynamic> json) {
|
||||
return ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: json['result'] as Map<String, dynamic>?,
|
||||
result: ElectrumWorkerScripthashesResponse.fromJson(json['result'] as Map<String, dynamic>),
|
||||
error: json['error'] as String?,
|
||||
id: json['id'] as int?,
|
||||
completed: json['completed'] as bool? ?? false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue