2023-07-26 18:07:30 +00:00
|
|
|
import 'dart:async';
|
2023-07-27 17:33:39 +00:00
|
|
|
import 'dart:io';
|
|
|
|
|
2023-07-26 18:07:30 +00:00
|
|
|
import 'package:protobuf/protobuf.dart';
|
2023-07-27 17:33:39 +00:00
|
|
|
import 'package:stackwallet/services/cashfusion/connection.dart';
|
|
|
|
import 'package:stackwallet/services/cashfusion/fusion.dart';
|
|
|
|
import 'package:stackwallet/services/cashfusion/fusion.pb.dart';
|
|
|
|
import 'package:stackwallet/services/cashfusion/socketwrapper.dart';
|
|
|
|
import 'package:stackwallet/services/cashfusion/util.dart';
|
2023-07-26 18:07:30 +00:00
|
|
|
|
|
|
|
typedef PbCreateFunc = GeneratedMessage Function();
|
|
|
|
|
|
|
|
Map<Type, PbCreateFunc> pbClassCreators = {
|
|
|
|
CovertResponse: () => CovertResponse(),
|
|
|
|
ClientMessage: () => ClientMessage(),
|
|
|
|
InputComponent: () => InputComponent(),
|
|
|
|
OutputComponent: () => OutputComponent(),
|
|
|
|
BlankComponent: () => BlankComponent(),
|
|
|
|
Component: () => Component(),
|
|
|
|
InitialCommitment: () => InitialCommitment(),
|
|
|
|
Proof: () => Proof(),
|
|
|
|
ClientHello: () => ClientHello(),
|
|
|
|
ServerHello: () => ServerHello(),
|
|
|
|
JoinPools: () => JoinPools(),
|
|
|
|
TierStatusUpdate: () => TierStatusUpdate(),
|
2023-07-27 17:33:39 +00:00
|
|
|
FusionBegin: () => FusionBegin(),
|
|
|
|
StartRound: () => StartRound(),
|
|
|
|
PlayerCommit: () => PlayerCommit(),
|
|
|
|
BlindSigResponses: () => BlindSigResponses(),
|
|
|
|
AllCommitments: () => AllCommitments(),
|
|
|
|
CovertComponent: () => CovertComponent(),
|
|
|
|
ShareCovertComponents: () => ShareCovertComponents(),
|
|
|
|
CovertTransactionSignature: () => CovertTransactionSignature(),
|
|
|
|
FusionResult: () => FusionResult(),
|
|
|
|
MyProofsList: () => MyProofsList(),
|
|
|
|
TheirProofsList: () => TheirProofsList(),
|
|
|
|
Blames: () => Blames(),
|
|
|
|
RestartRound: () => RestartRound(),
|
|
|
|
Error: () => Error(),
|
|
|
|
Ping: () => Ping(),
|
|
|
|
OK: () => OK(),
|
|
|
|
ClientMessage: () => ClientMessage(),
|
|
|
|
ServerMessage: () => ServerMessage(),
|
|
|
|
CovertMessage: () => CovertMessage(),
|
|
|
|
CovertResponse: () => CovertResponse()
|
2023-07-26 18:07:30 +00:00
|
|
|
};
|
|
|
|
|
2023-07-27 17:33:39 +00:00
|
|
|
Future<void> sendPb(
|
|
|
|
Connection connection, Type pbClass, GeneratedMessage subMsg,
|
|
|
|
{Duration? timeout}) async {
|
2023-07-26 18:07:30 +00:00
|
|
|
// Construct the outer message with the submessage.
|
|
|
|
|
|
|
|
if (pbClassCreators[pbClass] == null) {
|
|
|
|
print('pbClassCreators[pbClass] is null');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var pbMessage = pbClassCreators[pbClass]!()..mergeFromMessage(subMsg);
|
|
|
|
final msgBytes = pbMessage.writeToBuffer();
|
|
|
|
try {
|
|
|
|
await connection.sendMessage(msgBytes, timeout: timeout);
|
|
|
|
} on SocketException {
|
|
|
|
throw FusionError('Connection closed by remote');
|
|
|
|
} on TimeoutException {
|
|
|
|
throw FusionError('Timed out during send');
|
|
|
|
} catch (e) {
|
|
|
|
throw FusionError('Communications error: ${e.runtimeType}: $e');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 17:33:39 +00:00
|
|
|
Future<void> sendPb2(SocketWrapper socketwrapper, Connection connection,
|
|
|
|
Type pbClass, GeneratedMessage subMsg,
|
|
|
|
{Duration? timeout}) async {
|
2023-07-26 18:07:30 +00:00
|
|
|
// Construct the outer message with the submessage.
|
|
|
|
|
|
|
|
if (pbClassCreators[pbClass] == null) {
|
|
|
|
print('pbClassCreators[pbClass] is null');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var pbMessage = pbClassCreators[pbClass]!()..mergeFromMessage(subMsg);
|
|
|
|
final msgBytes = pbMessage.writeToBuffer();
|
|
|
|
try {
|
2023-07-27 17:33:39 +00:00
|
|
|
await connection.sendMessageWithSocketWrapper(socketwrapper, msgBytes,
|
|
|
|
timeout: timeout);
|
2023-07-26 18:07:30 +00:00
|
|
|
} on SocketException {
|
|
|
|
throw FusionError('Connection closed by remote');
|
|
|
|
} on TimeoutException {
|
|
|
|
throw FusionError('Timed out during send');
|
|
|
|
} catch (e) {
|
|
|
|
throw FusionError('Communications error: ${e.runtimeType}: $e');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 17:33:39 +00:00
|
|
|
Future<Tuple<GeneratedMessage, String>> recvPb2(SocketWrapper socketwrapper,
|
|
|
|
Connection connection, Type pbClass, List<String> expectedFieldNames,
|
|
|
|
{Duration? timeout}) async {
|
2023-07-26 18:07:30 +00:00
|
|
|
try {
|
2023-07-27 17:33:39 +00:00
|
|
|
List<int> blob =
|
|
|
|
await connection.recv_message2(socketwrapper, timeout: timeout);
|
2023-07-26 18:07:30 +00:00
|
|
|
|
|
|
|
var pbMessage = pbClassCreators[pbClass]!()..mergeFromBuffer(blob);
|
|
|
|
|
|
|
|
if (!pbMessage.isInitialized()) {
|
|
|
|
throw FusionError('Incomplete message received');
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var name in expectedFieldNames) {
|
|
|
|
var fieldInfo = pbMessage.info_.byName[name];
|
|
|
|
|
|
|
|
if (fieldInfo == null) {
|
|
|
|
throw FusionError('Expected field not found in message: $name');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pbMessage.hasField(fieldInfo.tagNumber)) {
|
|
|
|
return Tuple(pbMessage, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 17:33:39 +00:00
|
|
|
throw FusionError(
|
|
|
|
'None of the expected fields found in the received message');
|
2023-07-26 18:07:30 +00:00
|
|
|
} catch (e) {
|
|
|
|
// Handle different exceptions here
|
|
|
|
if (e is SocketException) {
|
|
|
|
throw FusionError('Connection closed by remote');
|
|
|
|
} else if (e is InvalidProtocolBufferException) {
|
|
|
|
throw FusionError('Message decoding error: ' + e.toString());
|
|
|
|
} else if (e is TimeoutException) {
|
|
|
|
throw FusionError('Timed out during receive');
|
|
|
|
} else if (e is OSError && e.errorCode == 9) {
|
|
|
|
throw FusionError('Connection closed by local');
|
|
|
|
} else {
|
2023-07-27 17:33:39 +00:00
|
|
|
throw FusionError(
|
|
|
|
'Communications error: ${e.runtimeType}: ${e.toString()}');
|
2023-07-26 18:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 17:33:39 +00:00
|
|
|
Future<Tuple<GeneratedMessage, String>> recvPb(
|
|
|
|
Connection connection, Type pbClass, List<String> expectedFieldNames,
|
|
|
|
{Duration? timeout}) async {
|
2023-07-26 18:07:30 +00:00
|
|
|
try {
|
|
|
|
List<int> blob = await connection.recv_message(timeout: timeout);
|
|
|
|
|
|
|
|
var pbMessage = pbClassCreators[pbClass]!()..mergeFromBuffer(blob);
|
|
|
|
|
|
|
|
if (!pbMessage.isInitialized()) {
|
|
|
|
throw FusionError('Incomplete message received');
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var name in expectedFieldNames) {
|
|
|
|
var fieldInfo = pbMessage.info_.byName[name];
|
|
|
|
|
|
|
|
if (fieldInfo == null) {
|
|
|
|
throw FusionError('Expected field not found in message: $name');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pbMessage.hasField(fieldInfo.tagNumber)) {
|
|
|
|
return Tuple(pbMessage, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 17:33:39 +00:00
|
|
|
throw FusionError(
|
|
|
|
'None of the expected fields found in the received message');
|
2023-07-26 18:07:30 +00:00
|
|
|
} catch (e) {
|
|
|
|
// Handle different exceptions here
|
|
|
|
if (e is SocketException) {
|
|
|
|
throw FusionError('Connection closed by remote');
|
|
|
|
} else if (e is InvalidProtocolBufferException) {
|
|
|
|
throw FusionError('Message decoding error: ' + e.toString());
|
|
|
|
} else if (e is TimeoutException) {
|
|
|
|
throw FusionError('Timed out during receive');
|
|
|
|
} else if (e is OSError && e.errorCode == 9) {
|
|
|
|
throw FusionError('Connection closed by local');
|
|
|
|
} else {
|
2023-07-27 17:33:39 +00:00
|
|
|
throw FusionError(
|
|
|
|
'Communications error: ${e.runtimeType}: ${e.toString()}');
|
2023-07-26 18:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|