-
Notifications
You must be signed in to change notification settings - Fork 19
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
PE-3173: Utilize Turbo Uploads for Quick Sync #1362
Merged
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
d36e8b6
feat(payment method selector): factors out a component in order to ma…
matibat c944ac1
feat(snapshots): let snapshots be uploaded with Turbo PE-3173
matibat 96c167f
feat(snapshots): missing await PE-3173
matibat ae2937d
Merge remote-tracking branch 'origin/dev' into PE-3173
matibat 2c461a9
feat(create snapshot cubit): free turbo uploads PE-3173
matibat 598c77e
feat(upload form): adds back the call to _getInsufficientBalanceMessa…
matibat 546900d
test(create snapshot): fixes nbronken tests PE-3173
matibat ea9f1c7
chore(create snapshot cubit & upload plan): cleanup PE-3173
matibat 6636abd
feat(new button): makes the option for snaqpshots be enabled even whe…
matibat 90f4685
Merge pull request #1382 from ardriveapp/PE-4665
matibat 91b078b
feat(snapshot & upload): makes no balance message be part of payment …
matibat 1a2e618
feat(upload cubit): makes the file upload modal show the correct not …
matibat 405149c
feat(create snapshot cubit): let the snapshot use turbo uploads when …
matibat 144aa4e
test(create snapshot cubit): fixes brokwn tests PE-4687
matibat abf45c6
feat(create snapshot cubit): corrects typo PE-4687
matibat 51d4d63
Merge pull request #1385 from ardriveapp/PE-4676
matibat 35e0cda
Merge pull request #1387 from ardriveapp/PE-4687
matibat 9b8bfdd
Merge remote-tracking branch 'origin/dev' into PE-3173
matibat 2e886f9
feat(create snapshot dialog): makes the turbo balance be refreshed on…
matibat 853a3dd
feat(pubspec): updates the ardrive-ui dep PE-4694
matibat 3b21e36
chore(create snapshot cubit): cleanup PE-4694
matibat b5ba8fc
feat(create snapshot cubit): adds a delay to ensure we'll read the co…
matibat 6d84457
feat(dev tools): adds optoins for disabling free uploads, setting a f…
matibat 4d1bf6c
feat(create snapshot cubit): update the state of the button after top…
matibat cf19253
test(create snapshot cubit): updates broken tests PE-4694
matibat dfb546d
chore(topup review view): corrects typo in a comment PE-4694
matibat faf9687
Merge pull request #1394 from ardriveapp/PE-4694
matibat f34cc58
Merge remote-tracking branch 'origin/dev' into PE-3173
matibat 26ef3cf
chore(create snapshot cubit): removes unnecessary non-null assertion …
matibat ef0493c
feat(pubspec): version bump of ardrive-ui PE-3173
matibat 2ab486d
Merge pull request #1402 from ardriveapp/PE-3173_dep_version_bump
matibat File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,23 +2,29 @@ import 'dart:async'; | |
import 'dart:convert'; | ||
import 'dart:io' show BytesBuilder; | ||
|
||
import 'package:ardrive/authentication/ardrive_auth.dart'; | ||
import 'package:ardrive/blocs/constants.dart'; | ||
import 'package:ardrive/blocs/profile/profile_cubit.dart'; | ||
import 'package:ardrive/blocs/upload/upload_cubit.dart'; | ||
import 'package:ardrive/core/upload/cost_calculator.dart'; | ||
import 'package:ardrive/entities/entities.dart'; | ||
import 'package:ardrive/entities/snapshot_entity.dart'; | ||
import 'package:ardrive/entities/string_types.dart'; | ||
import 'package:ardrive/models/daos/daos.dart'; | ||
import 'package:ardrive/services/arweave/arweave.dart'; | ||
import 'package:ardrive/services/config/app_config.dart'; | ||
import 'package:ardrive/services/pst/pst.dart'; | ||
import 'package:ardrive/turbo/services/payment_service.dart'; | ||
import 'package:ardrive/turbo/services/upload_service.dart'; | ||
import 'package:ardrive/turbo/turbo.dart'; | ||
import 'package:ardrive/turbo/utils/utils.dart'; | ||
import 'package:ardrive/utils/html/html_util.dart'; | ||
import 'package:ardrive/utils/logger/logger.dart'; | ||
import 'package:ardrive/utils/metadata_cache.dart'; | ||
import 'package:ardrive/utils/snapshots/height_range.dart'; | ||
import 'package:ardrive/utils/snapshots/range.dart'; | ||
import 'package:ardrive/utils/snapshots/snapshot_item_to_be_created.dart'; | ||
import 'package:arweave/arweave.dart'; | ||
import 'package:arweave/utils.dart'; | ||
import 'package:equatable/equatable.dart'; | ||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter_bloc/flutter_bloc.dart'; | ||
|
@@ -29,10 +35,15 @@ part 'create_snapshot_state.dart'; | |
|
||
class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | ||
final ArweaveService _arweave; | ||
final PaymentService _paymentService; | ||
final DriveDao _driveDao; | ||
final ProfileCubit _profileCubit; | ||
final PstService _pst; | ||
final TabVisibilitySingleton _tabVisibility; | ||
final TurboBalanceRetriever turboBalanceRetriever; | ||
final ArDriveAuth auth; | ||
final AppConfig appConfig; | ||
final TurboUploadService turboService; | ||
@visibleForTesting | ||
bool throwOnDataComputingForTesting; | ||
@visibleForTesting | ||
|
@@ -44,7 +55,22 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
late String _ownerAddress; | ||
late Range _range; | ||
late int _currentHeight; | ||
late Transaction _preparedTx; | ||
Uint8List? data; | ||
DataItem? _preparedDataItem; | ||
Transaction? _preparedTx; | ||
|
||
UploadMethod _uploadMethod = UploadMethod.ar; | ||
UploadCostEstimate _costEstimateAr = UploadCostEstimate.zero(); | ||
UploadCostEstimate _costEstimateTurbo = UploadCostEstimate.zero(); | ||
bool _hasNoTurboBalance = false; | ||
String _arBalance = ''; | ||
String _turboCredits = ''; | ||
BigInt _turboBalance = BigInt.zero; | ||
bool _isButtonToUploadEnabled = false; | ||
bool _isTurboUploadPossible = true; | ||
bool _sufficentCreditsBalance = false; | ||
bool _sufficientArBalance = false; | ||
bool _isFreeThanksToTurbo = false; | ||
|
||
bool _wasSnapshotDataComputingCanceled = false; | ||
|
||
|
@@ -53,14 +79,20 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
|
||
CreateSnapshotCubit({ | ||
required ArweaveService arweave, | ||
required PaymentService paymentService, | ||
required ProfileCubit profileCubit, | ||
required DriveDao driveDao, | ||
required PstService pst, | ||
required TabVisibilitySingleton tabVisibility, | ||
required this.turboBalanceRetriever, | ||
required this.auth, | ||
required this.appConfig, | ||
required this.turboService, | ||
this.throwOnDataComputingForTesting = false, | ||
this.throwOnSignTxForTesting = false, | ||
this.returnWithoutSigningForTesting = false, | ||
}) : _arweave = arweave, | ||
_paymentService = paymentService, | ||
_profileCubit = profileCubit, | ||
_driveDao = driveDao, | ||
_pst = pst, | ||
|
@@ -98,15 +130,15 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
|
||
_setupSnapshotEntityWithBlob(data); | ||
|
||
await _prepareAndSignTx( | ||
_snapshotEntity!, | ||
data, | ||
); | ||
|
||
final costResult = await _computeCostAndCheckBalance(); | ||
if (costResult == null) return; | ||
await _computeCost(); | ||
await _computeBalanceEstimate(); | ||
_computeIsSufficientBalance(); | ||
_computeIsTurboEnabled(); | ||
_computeIsFreeThanksToTurbo(); | ||
|
||
await _emitConfirming(costResult, data.length); | ||
await _emitConfirming( | ||
dataSize: data.length, | ||
); | ||
} | ||
|
||
bool _wasCancelled() { | ||
|
@@ -180,7 +212,7 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
|
||
Future<void> _prepareAndSignTx( | ||
SnapshotEntity snapshotEntity, | ||
Uint8List data, | ||
// Uint8List data, | ||
) async { | ||
logger.i('About to prepare and sign snapshot transaction'); | ||
|
||
|
@@ -191,10 +223,14 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
)); | ||
|
||
await prepareTx(isArConnectProfile); | ||
await _pst.addCommunityTipToTx(_preparedTx); | ||
// await _pst.addCommunityTipToTx(_preparedDataItem); // Turbo should be the one setting the tip, right? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we don't add the community tip in the client side for Turbo |
||
await signTx(isArConnectProfile); | ||
|
||
snapshotEntity.txId = _preparedTx.id; | ||
if (_uploadMethod == UploadMethod.ar) { | ||
snapshotEntity.txId = _preparedTx!.id; | ||
} else { | ||
snapshotEntity.txId = _preparedDataItem!.id; | ||
} | ||
} | ||
|
||
@visibleForTesting | ||
|
@@ -207,13 +243,22 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
'Preparing snapshot transaction with ${isArConnectProfile ? 'ArConnect' : 'JSON wallet'}', | ||
); | ||
|
||
_preparedTx = await _arweave.prepareEntityTx( | ||
_snapshotEntity!, | ||
wallet, | ||
null, | ||
// We'll sign it just after adding the tip | ||
skipSignature: true, | ||
); | ||
if (_uploadMethod == UploadMethod.ar) { | ||
_preparedTx = await _arweave.prepareEntityTx( | ||
_snapshotEntity!, | ||
wallet, | ||
null, | ||
// We'll sign it just after adding the tip | ||
skipSignature: true, | ||
); | ||
} else { | ||
_preparedDataItem = await _arweave.prepareEntityDataItem( | ||
_snapshotEntity!, | ||
wallet, | ||
// We'll sign it just after adding the tip | ||
skipSignature: true, | ||
); | ||
} | ||
} catch (e) { | ||
final isTabFocused = _tabVisibility.isTabFocused(); | ||
if (isArConnectProfile && !isTabFocused) { | ||
|
@@ -249,7 +294,11 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
return; | ||
} | ||
|
||
await _preparedTx.sign(wallet); | ||
if (_uploadMethod == UploadMethod.ar) { | ||
await _preparedTx!.sign(wallet); | ||
} else { | ||
await _preparedDataItem!.sign(wallet); | ||
} | ||
} catch (e) { | ||
final isTabFocused = _tabVisibility.isTabFocused(); | ||
if (isArConnectProfile && !isTabFocused) { | ||
|
@@ -323,39 +372,128 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
_snapshotEntity = snapshotEntity; | ||
} | ||
|
||
Future<BigInt?> _computeCostAndCheckBalance() async { | ||
final totalCost = _preparedTx.reward + _preparedTx.quantity; | ||
Future<void> _computeCost() async { | ||
final profileState = _profileCubit.state as ProfileLoggedIn; | ||
final wallet = profileState.wallet; | ||
|
||
final profile = _profileCubit.state as ProfileLoggedIn; | ||
final walletBalance = profile.walletBalance; | ||
UploadCostEstimateCalculatorForAR costCalculatorForAr = | ||
UploadCostEstimateCalculatorForAR( | ||
arweaveService: _arweave, | ||
pstService: _pst, | ||
arCostToUsd: ConvertArToUSD(arweave: _arweave), | ||
); | ||
|
||
if (walletBalance < totalCost) { | ||
emit(CreateSnapshotInsufficientBalance( | ||
walletBalance: walletBalance.toString(), | ||
arCost: winstonToAr(totalCost), | ||
)); | ||
return null; | ||
} | ||
final turboCostCalc = TurboCostCalculator(paymentService: _paymentService); | ||
TurboUploadCostCalculator costCalculatorForTurbo = | ||
TurboUploadCostCalculator( | ||
turboCostCalculator: turboCostCalc, | ||
priceEstimator: TurboPriceEstimator( | ||
wallet: wallet, | ||
paymentService: _paymentService, | ||
costCalculator: turboCostCalc, | ||
), | ||
); | ||
|
||
_costEstimateAr = await costCalculatorForAr.calculateCost( | ||
totalSize: _snapshotEntity!.data!.length, | ||
); | ||
_costEstimateTurbo = await costCalculatorForTurbo.calculateCost( | ||
totalSize: _snapshotEntity!.data!.length, | ||
); | ||
} | ||
|
||
return totalCost; | ||
Future<void> _computeBalanceEstimate() async { | ||
final profileState = _profileCubit.state as ProfileLoggedIn; | ||
final wallet = profileState.wallet; | ||
|
||
final turboBalance = | ||
await turboBalanceRetriever.getBalance(wallet).catchError((e) { | ||
logger.e('Error while retrieving turbo balance', e); | ||
return BigInt.zero; | ||
}); | ||
|
||
_turboBalance = turboBalance; | ||
_hasNoTurboBalance = turboBalance == BigInt.zero; | ||
_turboCredits = convertCreditsToLiteralString(turboBalance); | ||
_arBalance = convertCreditsToLiteralString(auth.currentUser!.walletBalance); | ||
} | ||
|
||
Future<void> _emitConfirming( | ||
BigInt totalCost, | ||
int dataSize, | ||
) async { | ||
final arUploadCost = winstonToAr(totalCost); | ||
void _computeIsTurboEnabled() async { | ||
bool isTurboEnabled = appConfig.useTurboUpload; | ||
_isTurboUploadPossible = isTurboEnabled && _sufficentCreditsBalance; | ||
} | ||
|
||
void _computeIsSufficientBalance() { | ||
final profileState = _profileCubit.state as ProfileLoggedIn; | ||
|
||
final double? usdUploadCost = await ConvertArToUSD(arweave: _arweave) | ||
.convertForUSD(double.parse(arUploadCost)); | ||
bool sufficientBalanceToPayWithAR = | ||
profileState.walletBalance >= _costEstimateAr.totalCost; | ||
bool sufficientBalanceToPayWithTurbo = | ||
_costEstimateTurbo.totalCost <= _turboBalance; | ||
|
||
_sufficientArBalance = sufficientBalanceToPayWithAR; | ||
_sufficentCreditsBalance = sufficientBalanceToPayWithTurbo; | ||
} | ||
|
||
void _computeIsFreeThanksToTurbo() { | ||
final allowedDataItemSizeForTurbo = appConfig.allowedDataItemSizeForTurbo; | ||
final isFreeThanksToTurbo = | ||
_snapshotEntity!.data!.length <= allowedDataItemSizeForTurbo; | ||
_isFreeThanksToTurbo = isFreeThanksToTurbo; | ||
} | ||
|
||
Future<void> _emitConfirming({required int dataSize}) async { | ||
emit(ConfirmingSnapshotCreation( | ||
snapshotSize: dataSize, | ||
arUploadCost: arUploadCost, | ||
usdUploadCost: usdUploadCost, | ||
costEstimateAr: _costEstimateAr, | ||
costEstimateTurbo: _costEstimateTurbo, | ||
hasNoTurboBalance: _hasNoTurboBalance, | ||
isTurboUploadPossible: _isTurboUploadPossible, | ||
arBalance: _arBalance, | ||
turboCredits: _turboCredits, | ||
uploadMethod: _uploadMethod, | ||
isButtonToUploadEnabled: _isButtonToUploadEnabled, | ||
sufficientBalanceToPayWithAr: _sufficientArBalance, | ||
sufficientBalanceToPayWithTurbo: _sufficentCreditsBalance, | ||
isFreeThanksToTurbo: _isFreeThanksToTurbo, | ||
)); | ||
} | ||
|
||
void setUploadMethod(UploadMethod method) { | ||
logger.d('Upload method set to $method'); | ||
_uploadMethod = method; | ||
|
||
_refreshIsButtonEnabled(); | ||
} | ||
|
||
void _refreshIsButtonEnabled() { | ||
_isButtonToUploadEnabled = false; | ||
if (state is ConfirmingSnapshotCreation) { | ||
final stateAsConfirming = state as ConfirmingSnapshotCreation; | ||
logger.d('Sufficient Balance To Pay With AR: $_sufficientArBalance'); | ||
|
||
if (_uploadMethod == UploadMethod.ar && _sufficientArBalance) { | ||
logger.d('Enabling button for AR payment method'); | ||
_isButtonToUploadEnabled = true; | ||
} else if (_uploadMethod == UploadMethod.turbo && | ||
stateAsConfirming.isTurboUploadPossible && | ||
_sufficentCreditsBalance) { | ||
logger.d('Enabling button for Turbo payment method'); | ||
_isButtonToUploadEnabled = true; | ||
} else if (stateAsConfirming.isFreeThanksToTurbo) { | ||
logger.d('Enabling button for free upload using Turbo'); | ||
_isButtonToUploadEnabled = true; | ||
} else { | ||
logger.d('Disabling button'); | ||
} | ||
|
||
emit(stateAsConfirming.copyWith( | ||
uploadMethod: _uploadMethod, | ||
isButtonToUploadEnabled: _isButtonToUploadEnabled, | ||
)); | ||
} | ||
} | ||
|
||
Future<Uint8List> _jsonMetadataOfTxId(String txId) async { | ||
final drive = | ||
await _driveDao.driveById(driveId: _driveId).getSingleOrNull(); | ||
|
@@ -396,10 +534,20 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
return; | ||
} | ||
|
||
await _prepareAndSignTx( | ||
_snapshotEntity!, | ||
); | ||
|
||
try { | ||
emit(UploadingSnapshot()); | ||
|
||
await _arweave.postTx(_preparedTx); | ||
if (_uploadMethod == UploadMethod.ar) { | ||
await _arweave.postTx(_preparedTx!); | ||
} else { | ||
await _postTurboDataItem( | ||
dataItem: _preparedDataItem!, | ||
); | ||
} | ||
|
||
emit(SnapshotUploadSuccess()); | ||
} catch (err, stacktrace) { | ||
|
@@ -408,6 +556,19 @@ class CreateSnapshotCubit extends Cubit<CreateSnapshotState> { | |
} | ||
} | ||
|
||
Future<void> _postTurboDataItem({required DataItem dataItem}) async { | ||
final profile = _profileCubit.state as ProfileLoggedIn; | ||
final wallet = profile.wallet; | ||
|
||
final addr = await wallet.getAddress(); | ||
logger.d('Posting snapshot transaction with $addr'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the |
||
|
||
await turboService.postDataItem( | ||
dataItem: dataItem, | ||
wallet: wallet, | ||
); | ||
} | ||
|
||
void cancelSnapshotCreation() { | ||
logger.i('User cancelled the snapshot creation'); | ||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code.