Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(DAPP-410): Time out in get first populated block #34

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ web_build_and_host:

file_test:
@reset
@flutter test test/shared/widgets/mobile_footer_tests.dart
@flutter test test/shared/widgets/mobile_footer_tests.dart
14 changes: 13 additions & 1 deletion lib/blocks/providers/block_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,27 @@ class BlockNotifier extends StateNotifier<AsyncValue<Map<int, Block>>> {
}
}

//TODO: figure out a better way since a ton of empty blocks means this is taking too long
final getFirstPopulatedBlockProvider =
FutureProvider.autoDispose.family<BlockResponse, Chains>((ref, selectedChain) async {
int depth = 0;
final genusClient = ref.read(genusProvider(selectedChain));
var nextBlock = await genusClient.getBlockByDepth(depth: depth);

// Get the current time
final startTime = DateTime.now();

//check that block has transactions
while (!nextBlock.block.fullBody.hasField(1)) {
// This will break the loop after 20 seconds
// Get the current time in each iteration
final currentTime = DateTime.now();
// Calculate the elapsed time
final elapsedTime = currentTime.difference(startTime);
// If the elapsed time is greater than the desired duration, break the loop
if (elapsedTime > const Duration(seconds: 20)) {
throw ('Error in blockProvider: getFirstPopulatedBlockProvider took too long');
}

depth++;
nextBlock = await genusClient.getBlockByDepth(depth: depth);
}
Expand Down
109 changes: 55 additions & 54 deletions lib/transactions/providers/transactions_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class TransactionsNotifier extends StateNotifier<AsyncValue<List<Transaction>>>
final Ref ref;
final Chains selectedChain;
TransactionsNotifier(this.ref, this.selectedChain) : super(const AsyncLoading()) {
getTransactions(setState: true);
getTransactions();
}

/// Gets a transaction from genus and adds it to state
Expand Down Expand Up @@ -163,67 +163,68 @@ class TransactionsNotifier extends StateNotifier<AsyncValue<List<Transaction>>>
///
/// If [setState] is true, it will update the state of the provider
/// If [setState] is false, it will not update the state of the provider
Future<List<Transaction>> getTransactions({
bool setState = false,
}) async {
Future<void> getTransactions() async {
if (selectedChain == const Chains.mock()) {
final transactions = List.generate(100, (index) => getMockTransaction());
if (setState) state = AsyncData(transactions);
return transactions;
state = AsyncData(transactions);
} else {
if (setState) state = const AsyncLoading();
state = const AsyncLoading();
final List<Transaction> transactions = [];
//get first populated block

var latestBlockRes = await ref.read(getFirstPopulatedBlockProvider(selectedChain).future);

final config = ref.read(configProvider.future);
final presentConfig = await config;

int transactionCount = latestBlockRes.block.fullBody.transactions.length;

var latestBlock = Block(
header: decodeId(latestBlockRes.block.header.headerId.value),
epoch: latestBlockRes.block.header.slot.toInt() ~/ presentConfig.config.epochLength.toInt(),
size: latestBlockRes.writeToBuffer().lengthInBytes.toDouble(),
height: latestBlockRes.block.header.height.toInt(),
slot: latestBlockRes.block.header.slot.toInt(),
timestamp: latestBlockRes.block.header.timestamp.toInt(),
transactionNumber: transactionCount,
);

//continue going through transactions
for (int i = 0; i < transactionCount; i++) {
//calculate transaction amount
var outputList = latestBlockRes.block.fullBody.transactions[i].outputs.toList();
var inputList = latestBlockRes.block.fullBody.transactions[i].inputs.toList();
var txAmount = calculateAmount(outputs: outputList);
var txFees = calculateFees(inputs: inputList, outputs: outputList);

transactions.add(
Transaction(
transactionId: decodeId(latestBlockRes.block.fullBody.transactions[i].transactionId.value),
status: TransactionStatus.pending,
block: latestBlock,
broadcastTimestamp: latestBlock.timestamp,
confirmedTimestamp: 0, //for the latest block, it will never be confirmed (confirmation depth is 5)
transactionType: TransactionType.transfer,
amount: txAmount.toDouble(),
quantity: txAmount.toDouble(),
transactionFee: txFees.toDouble(),
senderAddress:
latestBlockRes.block.fullBody.transactions[i].inputs.map((e) => decodeId(e.address.id.value)).toList(),
receiverAddress:
latestBlockRes.block.fullBody.transactions[i].outputs.map((e) => decodeId(e.address.id.value)).toList(),
transactionSize: latestBlockRes.block.fullBody.transactions[i].writeToBuffer().lengthInBytes.toDouble(),
name: latestBlockRes.block.fullBody.transactions[i].inputs[0].value.hasLvl() ? 'Lvl' : 'Topl',
),
try {
var latestBlockRes = await ref.read(getFirstPopulatedBlockProvider(selectedChain).future);
final config = ref.read(configProvider.future);
final presentConfig = await config;
int transactionCount = latestBlockRes.block.fullBody.transactions.length;
var latestBlock = Block(
header: decodeId(latestBlockRes.block.header.headerId.value),
epoch: latestBlockRes.block.header.slot.toInt() ~/ presentConfig.config.epochLength.toInt(),
size: latestBlockRes.writeToBuffer().lengthInBytes.toDouble(),
height: latestBlockRes.block.header.height.toInt(),
slot: latestBlockRes.block.header.slot.toInt(),
timestamp: latestBlockRes.block.header.timestamp.toInt(),
transactionNumber: transactionCount,
);
}
if (setState) {
//continue going through transactions
for (int i = 0; i < transactionCount; i++) {
//calculate transaction amount
var outputList = latestBlockRes.block.fullBody.transactions[i].outputs.toList();
var inputList = latestBlockRes.block.fullBody.transactions[i].inputs.toList();
var txAmount = calculateAmount(outputs: outputList);
var txFees = calculateFees(inputs: inputList, outputs: outputList);

final name = latestBlockRes.block.fullBody.transactions[i].inputs.isNotEmpty &&
latestBlockRes.block.fullBody.transactions[i].inputs[0].value.hasLvl()
? 'Lvl'
: 'Topl';

transactions.add(
Transaction(
transactionId: decodeId(latestBlockRes.block.fullBody.transactions[i].transactionId.value),
status: TransactionStatus.pending,
block: latestBlock,
broadcastTimestamp: latestBlock.timestamp,
confirmedTimestamp: 0, //for the latest block, it will never be confirmed (confirmation depth is 5)
transactionType: TransactionType.transfer,
amount: txAmount.toDouble(),
quantity: txAmount.toDouble(),
transactionFee: txFees.toDouble(),
senderAddress: latestBlockRes.block.fullBody.transactions[i].inputs
.map((e) => decodeId(e.address.id.value))
.toList(),
receiverAddress: latestBlockRes.block.fullBody.transactions[i].outputs
.map((e) => decodeId(e.address.id.value))
.toList(),
transactionSize: latestBlockRes.block.fullBody.transactions[i].writeToBuffer().lengthInBytes.toDouble(),
name: name,
),
);
}

state = AsyncData(transactions);
} catch (e) {
state = AsyncError(e, StackTrace.current);
}
return transactions;
}
}

Expand Down
4 changes: 3 additions & 1 deletion lib/transactions/sections/transaction_table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ class _TransactionTableScreenState extends ConsumerState<TransactionTableScreen>
])
]));
},
error: (error, stack) => const Text('Oops, something unexpected happened'),
error: (error, stack) {
return const Text('Oops, something unexpected happened');
},
loading: () => const Center(
child: CircularProgressIndicator(),
));
Expand Down
20 changes: 16 additions & 4 deletions lib/transactions/utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,33 @@ List<BigInt> getOutputBigInts({required List<UnspentTransactionOutput> outputs})
List<UnspentTransactionOutput> outputLvls = outputs.where((element) {
return element.value.hasLvl();
}).toList();

return outputLvls.map((e) {
return e.value.lvl.quantity.value.toBigInt;
}).toList();
try {
return outputLvls.map((e) {
return e.value.lvl.quantity.value.toBigInt;
}).toList();
} catch (e) {
return [];
}
}

BigInt calculateAmount({required List<UnspentTransactionOutput> outputs}) {
List<BigInt> outputBigInts = getOutputBigInts(outputs: outputs);

if (outputBigInts.isEmpty) {
return BigInt.zero;
}

return outputBigInts.reduce((value, element) => value + element);
}

BigInt calculateFees({required List<SpentTransactionOutput> inputs, required List<UnspentTransactionOutput> outputs}) {
List<BigInt> inputBigInts = getInputBigInts(inputs: inputs);
List<BigInt> outputBigInts = getOutputBigInts(outputs: outputs);

if (inputBigInts.isEmpty || outputBigInts.isEmpty) {
return BigInt.zero;
}

BigInt inputSum = inputBigInts.reduce((value, element) => value + element);
BigInt outputSum = outputBigInts.reduce((value, element) => value + element);

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: faucet
description: A new Flutter project.
description: Topl Ecosystem Faucet
KalervoHyyppa marked this conversation as resolved.
Show resolved Hide resolved
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev
Expand Down
65 changes: 65 additions & 0 deletions test/requests/request_tokens_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:faucet/home/sections/get_test_tokens.dart';
import 'package:faucet/requests/providers/requests_provider.dart';
import 'package:faucet/shared/services/hive/hive_service.dart';
import 'package:faucet/transactions/sections/transaction_table.dart';
import 'package:flutter_test/flutter_test.dart';

import '../essential_test_provider_widget.dart';
import '../required_test_class.dart';
import 'utils/mock_request_hive_utils.dart';

class RequiredRequestTokensTest extends RequiredTest {
Future<void> Function(TestScreenSizes testScreenSize) requestTokenTest;

RequiredRequestTokensTest({
required this.requestTokenTest,
required super.testScreenSize,
});

Future<void> runTests() async {
await requestTokenTest(testScreenSize);
}
}

void main() async {
final requestTests = RequiredRequestTokensTest(
requestTokenTest: (testScreenSize) => requestTokenTest(testScreenSize),
testScreenSize: TestScreenSizes.desktop,
);

await requestTests.runTests();
}

Future<void> requestTokenTest(TestScreenSizes testScreenSize) async =>
testWidgets('Should confirm that tokens are requested', (WidgetTester tester) async {
await tester.pumpWidget(
await essentialTestProviderWidget(
tester: tester,
testScreenSize: testScreenSize,
overrides: [hivePackageProvider.overrideWithValue(getMockRequestHive().mockHive)],
),
);
await tester.pumpAndSettle();
// click request token button
await tester.ensureVisible(find.byKey(TransactionTableScreen.requestTokensKey));
await tester.pumpAndSettle();
await tester.tap(find.byKey(TransactionTableScreen.requestTokensKey));
await tester.pumpAndSettle();
// check that the drawer is displayed
expect(find.byKey(GetTestTokens.getTestTokensKey), findsOneWidget);
// click the request token button
var requestTokenButton = find.byKey(GetTestTokens.requestTokenButtonKey);

await tester.ensureVisible(requestTokenButton);
await tester.pumpAndSettle();
await tester.tap(requestTokenButton);
await tester.pumpAndSettle();

bool successDialogIsDisplayed = find.byKey(SuccessDialog.requestSuccessDialogKey).evaluate().isNotEmpty;

if (successDialogIsDisplayed) {
//Show success dialog
expect(find.byKey(SuccessDialog.requestSuccessDialogKey), findsOneWidget);
await tester.pumpAndSettle();
}
});
Binary file modified web/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.