Skip to content

Commit

Permalink
get mempool instance from NetworkSettingsBloc
Browse files Browse the repository at this point in the history
  • Loading branch information
ubbabeck committed Oct 20, 2023
1 parent 09337ee commit 4ea84da
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 85 deletions.
34 changes: 24 additions & 10 deletions lib/bloc/network/network_settings_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'dart:convert';
import 'package:c_breez/bloc/network/network_settings_state.dart';
import 'package:c_breez/config.dart' as lib;
import 'package:c_breez/config.dart';
import 'package:c_breez/services/injector.dart';
import 'package:c_breez/utils/preferences.dart';
import 'package:logging/logging.dart';
import 'package:http/http.dart' as http;
Expand Down Expand Up @@ -47,7 +50,7 @@ class NetworkSettingsBloc extends Cubit<NetworkSettingsState> with HydratedMixin
_log.warning("Invalid mempool url: $mempoolUrl");
return false;
}
if (!await _testUri(uri) && !await _testUriSupportsMempoolApi(uri)) {
if (!await _testUriSupportsMempoolApi(uri)) {
_log.warning("Mempool url is not reachable: $mempoolUrl");
return false;
}
Expand Down Expand Up @@ -83,24 +86,35 @@ class NetworkSettingsBloc extends Cubit<NetworkSettingsState> with HydratedMixin
));
}

Future<bool> _testUri(Uri uri) async {
try {
final response = await _httpClient.get(uri);
return response.statusCode < 400;
} catch (e) {
_log.warning("Failed to test mempool url: $uri", e);
return false;
String formatTransactionUrl({required String txid, required String mempoolInstance}) {
return "$mempoolInstance/tx/$txid";
}

String formatRecomendedFeesUrl({required String mempoolInstance}) {
return "$mempoolInstance/api/v1/fees/recommended";
}

Future<String> get mempoolInstance async {
String? mempoolInstance = await ServiceInjector().preferences.getMempoolSpaceUrl();
if (mempoolInstance == null) {
final config = await Config.instance();
mempoolInstance = config.defaultMempoolUrl;
}
return mempoolInstance;
}

Future<bool> _testUriSupportsMempoolApi(Uri uri) async {
// We need to make sure that the mempool rest api is supported
// as the sdk depends on it.
uri = Uri.parse("${uri.toString()}/api/v1/fees/recommended");
uri = Uri.parse(formatRecomendedFeesUrl(mempoolInstance: uri.toString()));

try {
final response = await _httpClient.get(uri);
return response.statusCode == 200;
if (response.statusCode != 200) {
return false;
}
final Map<String, dynamic> body = jsonDecode(response.body);
return body.containsKey("fastestFee");
} catch (e) {
_log.warning("Failed to test mempool url: $uri", e);
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import 'package:breez_sdk/bridge_generated.dart' as sdk;
import 'package:breez_translations/breez_translations_locales.dart';
import 'package:c_breez/bloc/network/network_settings_bloc.dart';
import 'package:c_breez/models/payment_minutiae.dart';
import 'package:c_breez/routes/home/widgets/payments_list/dialog/tx_widget.dart';
import 'package:c_breez/utils/mempool_helper.dart';
import 'package:c_breez/widgets/loader.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class ClosedChannelPaymentDetailsWidget extends StatelessWidget {
final PaymentMinutiae paymentMinutiae;
final mempoolHelper = MempoolHelper();

ClosedChannelPaymentDetailsWidget({
const ClosedChannelPaymentDetailsWidget({
Key? key,
required this.paymentMinutiae,
}) : super(key: key);
Expand All @@ -19,65 +19,66 @@ class ClosedChannelPaymentDetailsWidget extends StatelessWidget {
Widget build(BuildContext context) {
final themeData = Theme.of(context);
final texts = context.texts();
final networkSettingsBloc = context.read<NetworkSettingsBloc>();

return FutureBuilder<String>(
future: mempoolHelper.mempoolInstance,
future: networkSettingsBloc.mempoolInstance,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
final mempoolInstance = snapshot.data!;
if (paymentMinutiae.status == sdk.PaymentStatus.Complete) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
RichText(
text: TextSpan(
style: themeData.dialogTheme.contentTextStyle,
text: texts.payment_details_dialog_closed_channel_local_wallet,
),
),
if (paymentMinutiae.paymentType == sdk.PaymentType.ClosedChannel &&
paymentMinutiae.closingTxid != null) ...[
TxWidget(
txURL: mempoolHelper.formatTransactionUrl(
txid: paymentMinutiae.closingTxid!, mempoolInstance: mempoolInstance),
txID: paymentMinutiae.closingTxid!,
),
],
],
);
}
// TODO pendingExpirationHeight
// TODO hoursToExpire
String estimation = texts.payment_details_dialog_closed_channel_transfer_no_estimation;
if (snapshot.connectionState != ConnectionState.done) {
return const Loader();
}

final mempoolInstance = snapshot.data!;
if (paymentMinutiae.status == sdk.PaymentStatus.Complete) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
RichText(
text: TextSpan(
style: themeData.dialogTheme.contentTextStyle,
text: estimation,
text: texts.payment_details_dialog_closed_channel_local_wallet,
),
),
if (paymentMinutiae.fundingTxid != null) ...[
TxWidget(
txURL: mempoolHelper.formatTransactionUrl(
txid: paymentMinutiae.fundingTxid!, mempoolInstance: mempoolInstance),
txID: paymentMinutiae.fundingTxid!,
),
],
if (paymentMinutiae.closingTxid != null) ...[
if (paymentMinutiae.paymentType == sdk.PaymentType.ClosedChannel &&
paymentMinutiae.closingTxid != null) ...[
TxWidget(
txURL: mempoolHelper.formatTransactionUrl(
txURL: networkSettingsBloc.formatTransactionUrl(
txid: paymentMinutiae.closingTxid!, mempoolInstance: mempoolInstance),
txID: paymentMinutiae.closingTxid!,
),
]
],
],
);
} else {
return const Loader();
}
// TODO pendingExpirationHeight
// TODO hoursToExpire
String estimation = texts.payment_details_dialog_closed_channel_transfer_no_estimation;

return Column(
mainAxisSize: MainAxisSize.min,
children: [
RichText(
text: TextSpan(
style: themeData.dialogTheme.contentTextStyle,
text: estimation,
),
),
if (paymentMinutiae.fundingTxid != null) ...[
TxWidget(
txURL: networkSettingsBloc.formatTransactionUrl(
txid: paymentMinutiae.fundingTxid!, mempoolInstance: mempoolInstance),
txID: paymentMinutiae.fundingTxid!,
),
],
if (paymentMinutiae.closingTxid != null) ...[
TxWidget(
txURL: networkSettingsBloc.formatTransactionUrl(
txid: paymentMinutiae.closingTxid!, mempoolInstance: mempoolInstance),
txID: paymentMinutiae.closingTxid!,
),
]
],
);
},
);
}
Expand Down
11 changes: 6 additions & 5 deletions lib/routes/subswap/swap/widgets/inprogress_swap.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import 'package:breez_sdk/bridge_generated.dart';
import 'package:breez_translations/breez_translations_locales.dart';
import 'package:c_breez/bloc/network/network_settings_bloc.dart';
import 'package:c_breez/services/injector.dart';
import 'package:c_breez/utils/mempool_helper.dart';
import 'package:c_breez/widgets/flushbar.dart';
import 'package:c_breez/widgets/link_launcher.dart';
import 'package:c_breez/widgets/loader.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class SwapInprogress extends StatelessWidget {
final SwapInfo swap;
Expand Down Expand Up @@ -44,16 +45,16 @@ class SwapInprogress extends StatelessWidget {

class _TxLink extends StatelessWidget {
final String txid;
final mempoolExplorer = MempoolHelper();

_TxLink({required this.txid});
const _TxLink({required this.txid});

@override
Widget build(BuildContext context) {
final text = context.texts();
final networkSettingsBloc = context.read<NetworkSettingsBloc>();

return FutureBuilder(
future: mempoolExplorer.mempoolInstance,
future: networkSettingsBloc.mempoolInstance,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const Loader();
Expand All @@ -62,7 +63,7 @@ class _TxLink extends StatelessWidget {

return LinkLauncher(
linkName: txid,
linkAddress: mempoolExplorer.formatTransactionUrl(txid: txid, mempoolInstance: mempoolInstance),
linkAddress: networkSettingsBloc.formatTransactionUrl(txid: txid, mempoolInstance: mempoolInstance),
onCopy: () {
ServiceInjector().device.setClipboardText(txid);
showFlushbar(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:breez_sdk/bridge_generated.dart' as sdk;
import 'package:breez_translations/breez_translations_locales.dart';
import 'package:c_breez/bloc/network/network_settings_bloc.dart';
import 'package:c_breez/services/injector.dart';
import 'package:c_breez/utils/mempool_helper.dart';
import 'package:c_breez/widgets/flushbar.dart';
import 'package:c_breez/widgets/link_launcher.dart';
import 'package:c_breez/widgets/loader.dart';
Expand Down Expand Up @@ -40,23 +40,23 @@ class ReverseSwapInprogress extends StatelessWidget {

class _TxLink extends StatelessWidget {
final String txid;
final mempoolHelper = MempoolHelper();

_TxLink({required this.txid});
const _TxLink({required this.txid});

@override
Widget build(BuildContext context) {
final text = context.texts();
final networkSettingsBloc = context.read<NetworkSettingsBloc>();

return FutureBuilder(
future: mempoolHelper.mempoolInstance,
future: networkSettingsBloc.mempoolInstance,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const Loader();
}

final transactionUrl =
mempoolHelper.formatTransactionUrl(mempoolInstance: snapshot.data!, txid: txid);
networkSettingsBloc.formatTransactionUrl(mempoolInstance: snapshot.data!, txid: txid);

return LinkLauncher(
linkName: txid,
Expand Down
17 changes: 0 additions & 17 deletions lib/utils/mempool_helper.dart

This file was deleted.

32 changes: 27 additions & 5 deletions test/bloc/network/network_settings_bloc_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:c_breez/bloc/network/network_settings_bloc.dart';
import 'package:c_breez/bloc/network/network_settings_state.dart';
import 'package:c_breez/services/injector.dart';
Expand All @@ -12,6 +14,17 @@ import '../../unit_logger.dart';
import '../../utils/fake_path_provider_platform.dart';
import '../../utils/hydrated_bloc_storage.dart';

String get _recomendedMockFeesResponse {
final Map<String, dynamic> recomendedFees = {
"fastestFee": 1,
"halfHourFee": 1,
"hourFee": 1,
"economyFee": 1,
"minimumFee": 1
};
return jsonEncode(recomendedFees);
}

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final platform = FakePathProviderPlatform();
Expand Down Expand Up @@ -75,17 +88,23 @@ void main() {

test('set mempool space url with a valid url should set on the preferences', () async {
const url = "https://mempool.space";
httpClient.getAnswer["$url/api/v1/fees/recommended"] = http.Response("{}", 200);

httpClient.getAnswer[url] = http.Response("{}", 200);
final bloc = make();

httpClient.getAnswer[bloc.formatRecomendedFeesUrl(mempoolInstance: url)] =
http.Response(_recomendedMockFeesResponse, 200);
final result = await bloc.setMempoolUrl(url);
expect(result, true);
expect(injector.preferencesMock.setMempoolSpaceUrlUrl, url);
});

test('set mempool space url with a valid url missing scheme should set on the preferences', () async {
const url = "mempool.space";
httpClient.getAnswer["https://$url/api/v1/fees/recommended"] = http.Response("{}", 200);

final bloc = make();
httpClient.getAnswer["https://${bloc.formatRecomendedFeesUrl(mempoolInstance: url)}"] =
http.Response(_recomendedMockFeesResponse, 200);
final result = await bloc.setMempoolUrl(url);
expect(result, true);
expect(injector.preferencesMock.setMempoolSpaceUrlUrl, "https://$url");
Expand All @@ -101,26 +120,29 @@ void main() {

test('set mempool space url with an ip should should set on the preferences', () async {
const url = "https://192.168.15.2";
httpClient.getAnswer["$url/api/v1/fees/recommended"] = http.Response("{}", 200);
final bloc = make();
httpClient.getAnswer[bloc.formatRecomendedFeesUrl(mempoolInstance: url)] =
http.Response(_recomendedMockFeesResponse, 200);
final result = await bloc.setMempoolUrl(url);
expect(result, true);
expect(injector.preferencesMock.setMempoolSpaceUrlUrl, url);
});

test('set mempool space url with an ip and port should should set on the preferences', () async {
const url = "https://192.168.15.2:3006";
httpClient.getAnswer["$url/api/v1/fees/recommended"] = http.Response("{}", 200);
final bloc = make();
httpClient.getAnswer[bloc.formatRecomendedFeesUrl(mempoolInstance: url)] =
http.Response(_recomendedMockFeesResponse, 200);
final result = await bloc.setMempoolUrl(url);
expect(result, true);
expect(injector.preferencesMock.setMempoolSpaceUrlUrl, url);
});

test('set mempool space url with an ip missing scheme should should set on the preferences', () async {
const url = "192.168.15.2";
httpClient.getAnswer["https://$url/api/v1/fees/recommended"] = http.Response("{}", 200);
final bloc = make();
httpClient.getAnswer["https://${bloc.formatRecomendedFeesUrl(mempoolInstance: url)}"] =
http.Response(_recomendedMockFeesResponse, 200);
final result = await bloc.setMempoolUrl(url);
expect(result, true);
expect(injector.preferencesMock.setMempoolSpaceUrlUrl, "https://$url");
Expand Down

0 comments on commit 4ea84da

Please sign in to comment.