From 1646a67117e69a9f5b28aed768775b1c3fa50a03 Mon Sep 17 00:00:00 2001 From: Rafael Saes Date: Fri, 20 Dec 2024 20:18:32 -0300 Subject: [PATCH] fix: scan --- .../lib/electrum_worker/electrum_worker.dart | 182 +++++++++--------- cw_bitcoin/pubspec.yaml | 2 +- 2 files changed, 94 insertions(+), 90 deletions(-) diff --git a/cw_bitcoin/lib/electrum_worker/electrum_worker.dart b/cw_bitcoin/lib/electrum_worker/electrum_worker.dart index 758934e03..37dbe30f0 100644 --- a/cw_bitcoin/lib/electrum_worker/electrum_worker.dart +++ b/cw_bitcoin/lib/electrum_worker/electrum_worker.dart @@ -3,11 +3,9 @@ import 'dart:convert'; import 'dart:isolate'; import 'package:bitcoin_base/bitcoin_base.dart'; -import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; -import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_worker/electrum_worker_methods.dart'; @@ -17,7 +15,6 @@ import 'package:cw_core/sync_status.dart'; import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; -import 'package:http/http.dart' as http; import 'package:rxdart/rxdart.dart'; import 'package:sp_scanner/sp_scanner.dart'; @@ -108,7 +105,6 @@ class ElectrumWorker { ); break; case ElectrumWorkerMethods.stopScanningMethod: - printV("Worker: received message: $message"); await _handleStopScanning( ElectrumWorkerStopScanningRequest.fromJson(messageJson), ); @@ -437,49 +433,10 @@ class ElectrumWorker { if (getTime && _walletType == WalletType.bitcoin) { if (mempoolAPIEnabled) { try { - // TODO: mempool api class - final txVerbose = await http - .get( - Uri.parse( - "https://mempool.cakewallet.com/api/v1/tx/$hash/status", - ), - ) - .timeout(const Duration(seconds: 5)); - - if (txVerbose.statusCode == 200 && - txVerbose.body.isNotEmpty && - jsonDecode(txVerbose.body) != null) { - height = jsonDecode(txVerbose.body)['block_height'] as int; - - final blockHash = await http - .get( - Uri.parse( - "https://mempool.cakewallet.com/api/v1/block-height/$height", - ), - ) - .timeout(const Duration(seconds: 5)); - - if (blockHash.statusCode == 200 && blockHash.body.isNotEmpty) { - final blockResponse = await http - .get( - Uri.parse( - "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}", - ), - ) - .timeout(const Duration(seconds: 5)); - - if (blockResponse.statusCode == 200 && - blockResponse.body.isNotEmpty && - jsonDecode(blockResponse.body)['timestamp'] != null) { - time = int.parse(jsonDecode(blockResponse.body)['timestamp'].toString()); - - if (date != null) { - final newDate = DateTime.fromMillisecondsSinceEpoch(time * 1000); - isDateValidated = newDate == date; - } - } - } - } + final dates = await getTxDate(hash, _network!, date: date); + time = dates.time; + height = dates.height; + isDateValidated = dates.isDateValidated; } catch (_) {} } } @@ -604,15 +561,12 @@ class ElectrumWorker { int initialSyncHeight = syncHeight; final receivers = scanData.silentPaymentsWallets.map( - (wallet) { - return Receiver( - wallet.b_scan.toHex(), - wallet.B_spend.toHex(), - scanData.network == BitcoinNetwork.testnet, - scanData.labelIndexes, - scanData.labelIndexes.length, - ); - }, + (wallet) => Receiver( + wallet.b_scan.toHex(), + wallet.B_spend.toHex(), + scanData.network == BitcoinNetwork.testnet, + scanData.labelIndexes, + ), ); int getCountPerRequest(int syncHeight) { @@ -640,7 +594,7 @@ class ElectrumWorker { _scanningStream = await scanningClient!.subscribe(req); - void listenFn(Map event, ElectrumTweaksSubscribe req) { + void listenFn(Map event, ElectrumTweaksSubscribe req) async { final response = req.onResponse(event); if (response == null || _scanningStream == null) { @@ -691,24 +645,29 @@ class ElectrumWorker { final tweak = tweakData.tweak; try { - // scanOutputs called from rust here final addToWallet = {}; receivers.forEach((receiver) { + // scanOutputs called from rust here final scanResult = scanOutputs(outputPubkeys.keys.toList(), tweak, receiver); - addToWallet.addAll(scanResult); - }); - // final addToWallet = scanOutputs( - // outputPubkeys.keys.toList(), - // tweak, - // receivers.last, - // ); + if (scanResult.isEmpty) { + return; + } + if (addToWallet[receiver.BSpend] == null) { + addToWallet[receiver.BSpend] = scanResult; + } else { + addToWallet[receiver.BSpend].addAll(scanResult); + } + }); + + print("ADDTO WALLET: $addToWallet"); if (addToWallet.isEmpty) { // no results tx, continue to next tx continue; } + print(scanData.labels); // placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s) final txInfo = ElectrumTransactionInfo( @@ -720,40 +679,41 @@ class ElectrumWorker { direction: TransactionDirection.incoming, isPending: false, isReplaced: false, - // TODO: tx time mempool api - date: scanData.network == BitcoinNetwork.mainnet - ? getDateByBitcoinHeight(tweakHeight) - : DateTime.now(), + date: DateTime.fromMillisecondsSinceEpoch( + (await getTxDate(txid, scanData.network)).time! * 1000, + ), confirmations: scanData.chainTip - tweakHeight + 1, unspents: [], isReceivedSilentPayment: true, ); - addToWallet.forEach((label, value) { - (value as Map).forEach((output, tweak) { - final t_k = tweak.toString(); + addToWallet.forEach((BSpend, result) { + result.forEach((label, value) { + (value as Map).forEach((output, tweak) { + final t_k = tweak.toString(); - final receivingOutputAddress = ECPublic.fromHex(output) - .toTaprootAddress(tweak: false) - .toAddress(scanData.network); + final receivingOutputAddress = ECPublic.fromHex(output) + .toTaprootAddress(tweak: false) + .toAddress(scanData.network); - final matchingOutput = outputPubkeys[output]!; - final amount = matchingOutput.amount; - final pos = matchingOutput.vout; + final matchingOutput = outputPubkeys[output]!; + final amount = matchingOutput.amount; + final pos = matchingOutput.vout; - final receivedAddressRecord = BitcoinReceivedSPAddressRecord( - receivingOutputAddress, - labelIndex: 1, // TODO: get actual index/label - isUsed: true, - tweak: t_k, - txCount: 1, - balance: amount, - ); + final receivedAddressRecord = BitcoinReceivedSPAddressRecord( + receivingOutputAddress, + labelIndex: 1, // TODO: get actual index/label + isUsed: true, + tweak: t_k, + txCount: 1, + balance: amount, + ); - final unspent = BitcoinUnspent(receivedAddressRecord, txid, amount, pos); + final unspent = BitcoinUnspent(receivedAddressRecord, txid, amount, pos); - txInfo.unspents!.add(unspent); - txInfo.amount += unspent.value; + txInfo.unspents!.add(unspent); + txInfo.amount += unspent.value; + }); }); }); @@ -947,3 +907,47 @@ class ScanNode { ScanNode(this.uri, this.useSSL); } + +class DateResult { + final int? time; + final int? height; + final bool? isDateValidated; + + DateResult({this.time, this.height, this.isDateValidated}); +} + +Future getTxDate( + String txid, + BasedUtxoNetwork network, { + DateTime? date, +}) async { + int? time; + int? height; + bool? isDateValidated; + + final mempoolApi = ApiProvider.fromMempool( + network, + baseUrl: "http://mempool.cakewallet.com:8999/api/v1", + ); + + try { + final txVerbose = await mempoolApi.getTransaction(txid); + + final status = txVerbose.status; + height = status.blockHeight; + + if (height != null) { + final blockHash = await mempoolApi.getBlockHeight(height); + final block = await mempoolApi.getBlock(blockHash); + + time = int.parse(block['timestamp'].toString()); + + if (date != null) { + final newDate = DateTime.fromMillisecondsSinceEpoch(time * 1000); + isDateValidated = newDate == date; + } + } + } catch (_) {} + + return DateResult(time: time, height: height, isDateValidated: isDateValidated); +} diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 9c7c41420..9b606066a 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: sp_scanner: git: url: https://github.com/cake-tech/sp_scanner.git - ref: cake-update-v3 + ref: cake-update-v4 bech32: git: url: https://github.com/cake-tech/bech32.git