fix: scan

This commit is contained in:
Rafael Saes 2024-12-20 20:18:32 -03:00
parent 51590a668d
commit 1646a67117
2 changed files with 94 additions and 90 deletions

View file

@ -3,11 +3,9 @@ import 'dart:convert';
import 'dart:isolate'; import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart'; 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_address_record.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_bitcoin/bitcoin_unspent.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_balance.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/electrum_worker/electrum_worker_methods.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/transaction_direction.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:http/http.dart' as http;
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:sp_scanner/sp_scanner.dart'; import 'package:sp_scanner/sp_scanner.dart';
@ -108,7 +105,6 @@ class ElectrumWorker {
); );
break; break;
case ElectrumWorkerMethods.stopScanningMethod: case ElectrumWorkerMethods.stopScanningMethod:
printV("Worker: received message: $message");
await _handleStopScanning( await _handleStopScanning(
ElectrumWorkerStopScanningRequest.fromJson(messageJson), ElectrumWorkerStopScanningRequest.fromJson(messageJson),
); );
@ -437,49 +433,10 @@ class ElectrumWorker {
if (getTime && _walletType == WalletType.bitcoin) { if (getTime && _walletType == WalletType.bitcoin) {
if (mempoolAPIEnabled) { if (mempoolAPIEnabled) {
try { try {
// TODO: mempool api class final dates = await getTxDate(hash, _network!, date: date);
final txVerbose = await http time = dates.time;
.get( height = dates.height;
Uri.parse( isDateValidated = dates.isDateValidated;
"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;
}
}
}
}
} catch (_) {} } catch (_) {}
} }
} }
@ -604,15 +561,12 @@ class ElectrumWorker {
int initialSyncHeight = syncHeight; int initialSyncHeight = syncHeight;
final receivers = scanData.silentPaymentsWallets.map( final receivers = scanData.silentPaymentsWallets.map(
(wallet) { (wallet) => Receiver(
return Receiver( wallet.b_scan.toHex(),
wallet.b_scan.toHex(), wallet.B_spend.toHex(),
wallet.B_spend.toHex(), scanData.network == BitcoinNetwork.testnet,
scanData.network == BitcoinNetwork.testnet, scanData.labelIndexes,
scanData.labelIndexes, ),
scanData.labelIndexes.length,
);
},
); );
int getCountPerRequest(int syncHeight) { int getCountPerRequest(int syncHeight) {
@ -640,7 +594,7 @@ class ElectrumWorker {
_scanningStream = await scanningClient!.subscribe(req); _scanningStream = await scanningClient!.subscribe(req);
void listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) { void listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) async {
final response = req.onResponse(event); final response = req.onResponse(event);
if (response == null || _scanningStream == null) { if (response == null || _scanningStream == null) {
@ -691,24 +645,29 @@ class ElectrumWorker {
final tweak = tweakData.tweak; final tweak = tweakData.tweak;
try { try {
// scanOutputs called from rust here
final addToWallet = {}; final addToWallet = {};
receivers.forEach((receiver) { receivers.forEach((receiver) {
// scanOutputs called from rust here
final scanResult = scanOutputs(outputPubkeys.keys.toList(), tweak, receiver); final scanResult = scanOutputs(outputPubkeys.keys.toList(), tweak, receiver);
addToWallet.addAll(scanResult); if (scanResult.isEmpty) {
}); return;
// final addToWallet = scanOutputs( }
// outputPubkeys.keys.toList(),
// tweak,
// receivers.last,
// );
if (addToWallet[receiver.BSpend] == null) {
addToWallet[receiver.BSpend] = scanResult;
} else {
addToWallet[receiver.BSpend].addAll(scanResult);
}
});
print("ADDTO WALLET: $addToWallet");
if (addToWallet.isEmpty) { if (addToWallet.isEmpty) {
// no results tx, continue to next tx // no results tx, continue to next tx
continue; continue;
} }
print(scanData.labels);
// placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s) // placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s)
final txInfo = ElectrumTransactionInfo( final txInfo = ElectrumTransactionInfo(
@ -720,40 +679,41 @@ class ElectrumWorker {
direction: TransactionDirection.incoming, direction: TransactionDirection.incoming,
isPending: false, isPending: false,
isReplaced: false, isReplaced: false,
// TODO: tx time mempool api date: DateTime.fromMillisecondsSinceEpoch(
date: scanData.network == BitcoinNetwork.mainnet (await getTxDate(txid, scanData.network)).time! * 1000,
? getDateByBitcoinHeight(tweakHeight) ),
: DateTime.now(),
confirmations: scanData.chainTip - tweakHeight + 1, confirmations: scanData.chainTip - tweakHeight + 1,
unspents: [], unspents: [],
isReceivedSilentPayment: true, isReceivedSilentPayment: true,
); );
addToWallet.forEach((label, value) { addToWallet.forEach((BSpend, result) {
(value as Map<String, dynamic>).forEach((output, tweak) { result.forEach((label, value) {
final t_k = tweak.toString(); (value as Map<String, dynamic>).forEach((output, tweak) {
final t_k = tweak.toString();
final receivingOutputAddress = ECPublic.fromHex(output) final receivingOutputAddress = ECPublic.fromHex(output)
.toTaprootAddress(tweak: false) .toTaprootAddress(tweak: false)
.toAddress(scanData.network); .toAddress(scanData.network);
final matchingOutput = outputPubkeys[output]!; final matchingOutput = outputPubkeys[output]!;
final amount = matchingOutput.amount; final amount = matchingOutput.amount;
final pos = matchingOutput.vout; final pos = matchingOutput.vout;
final receivedAddressRecord = BitcoinReceivedSPAddressRecord( final receivedAddressRecord = BitcoinReceivedSPAddressRecord(
receivingOutputAddress, receivingOutputAddress,
labelIndex: 1, // TODO: get actual index/label labelIndex: 1, // TODO: get actual index/label
isUsed: true, isUsed: true,
tweak: t_k, tweak: t_k,
txCount: 1, txCount: 1,
balance: amount, balance: amount,
); );
final unspent = BitcoinUnspent(receivedAddressRecord, txid, amount, pos); final unspent = BitcoinUnspent(receivedAddressRecord, txid, amount, pos);
txInfo.unspents!.add(unspent); txInfo.unspents!.add(unspent);
txInfo.amount += unspent.value; txInfo.amount += unspent.value;
});
}); });
}); });
@ -947,3 +907,47 @@ class ScanNode {
ScanNode(this.uri, this.useSSL); ScanNode(this.uri, this.useSSL);
} }
class DateResult {
final int? time;
final int? height;
final bool? isDateValidated;
DateResult({this.time, this.height, this.isDateValidated});
}
Future<DateResult> 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<MempoolTransaction>(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);
}

View file

@ -36,7 +36,7 @@ dependencies:
sp_scanner: sp_scanner:
git: git:
url: https://github.com/cake-tech/sp_scanner.git url: https://github.com/cake-tech/sp_scanner.git
ref: cake-update-v3 ref: cake-update-v4
bech32: bech32:
git: git:
url: https://github.com/cake-tech/bech32.git url: https://github.com/cake-tech/bech32.git