mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-29 21:55:58 +00:00
query electrum for missing tx info
This commit is contained in:
parent
93cfca7ddf
commit
ef38e58b57
4 changed files with 107 additions and 14 deletions
|
@ -726,6 +726,14 @@ class ElectrumX {
|
|||
return {"rawtx": response["result"] as String};
|
||||
}
|
||||
|
||||
if (response["result"] == null) {
|
||||
Logging.instance.log(
|
||||
"getTransaction($txHash) returned null response",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
throw 'getTransaction($txHash) returned null response';
|
||||
}
|
||||
|
||||
return Map<String, dynamic>.from(response["result"] as Map);
|
||||
} catch (e) {
|
||||
Logging.instance.log(
|
||||
|
|
|
@ -11,15 +11,18 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:fusiondart/src/models/address.dart' as fusion_address;
|
||||
import 'package:fusiondart/src/models/input.dart' as fusion_input;
|
||||
import 'package:fusiondart/src/models/output.dart' as fusion_output;
|
||||
import 'package:fusiondart/src/models/transaction.dart' as fusion_tx;
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
|
||||
import 'package:stackwallet/models/isar/models/blockchain_data/input.dart';
|
||||
import 'package:stackwallet/models/isar/models/blockchain_data/output.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
part 'transaction.g.dart';
|
||||
|
@ -237,19 +240,57 @@ class Transaction {
|
|||
}
|
||||
|
||||
// Convert to fusiondart's Transaction type.
|
||||
fusion_tx.Transaction toFusionTransaction() {
|
||||
//
|
||||
// This is bad because in the FusionWalletInterface in getTransactionsByAddress
|
||||
// we already getAllTransactions, then for each transaction here we also getTransaction
|
||||
// for each transaction again. But the data we need--the input's value--isn't
|
||||
// here anyways.
|
||||
Future<fusion_tx.Transaction> toFusionTransaction(
|
||||
CachedElectrumX cachedElectrumX) async {
|
||||
// Initialize Fusion Dart's Transaction object.
|
||||
fusion_tx.Transaction fusionTransaction = fusion_tx.Transaction();
|
||||
|
||||
// Map the Inputs and Outputs to Fusion Dart's format
|
||||
fusionTransaction.Inputs = inputs.map((e) {
|
||||
return fusion_input.Input(
|
||||
prevTxid: utf8.encode(e.txid),
|
||||
prevIndex: e.vout,
|
||||
pubKey: utf8.encode(address.value.toString()), // TODO fix public key.
|
||||
amount: amount, // TODO is this valid? Probably not.
|
||||
// Map the Inputs and Outputs to Fusion Dart's format.
|
||||
//
|
||||
// This takes an exqcessive amount of time because we have to get the
|
||||
// transaction for each input. We already have the transaction for each
|
||||
// input in getTransactionsByAddress, but we don't have the input's value.
|
||||
// So we have to get the transaction again here.
|
||||
fusionTransaction.Inputs = await Future.wait(inputs.map((e) async {
|
||||
// Find input amount.
|
||||
print("2 getting tx ${e.txid}");
|
||||
Map<String, dynamic> _tx = await cachedElectrumX.getTransaction(
|
||||
coin: Coin.bitcoincash,
|
||||
txHash: e.txid,
|
||||
verbose: true); // TODO is verbose needed?
|
||||
|
||||
// Check if output amount is available.
|
||||
if (_tx == null) {
|
||||
throw Exception("Transaction not found for input: ${e.txid}");
|
||||
}
|
||||
if (_tx["vout"] == null) {
|
||||
throw Exception("Vout in transaction ${e.txid} is null");
|
||||
}
|
||||
if (_tx["vout"][e.vout] == null) {
|
||||
throw Exception("Vout index ${e.vout} in transaction is null");
|
||||
}
|
||||
if (_tx["vout"][e.vout]["value"] == null) {
|
||||
throw Exception("Value of vout index ${e.vout} in transaction is null");
|
||||
}
|
||||
|
||||
// Assign vout value to amount.
|
||||
final value = Amount.fromDecimal(
|
||||
Decimal.parse(_tx["vout"][e.vout]["value"].toString()),
|
||||
fractionDigits: Coin.bitcoincash.decimals,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
return fusion_input.Input(
|
||||
prevTxid: utf8.encode(e.txid), // TODO verify this is what we want.
|
||||
prevIndex: e.vout, // TODO verify this is what we want.
|
||||
pubKey: utf8.encode(address.value.toString()), // TODO fix public key.
|
||||
amount: value.raw.toInt(),
|
||||
);
|
||||
}).toList());
|
||||
|
||||
fusionTransaction.Outputs = outputs.map((e) {
|
||||
/*
|
||||
|
|
|
@ -140,6 +140,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
coin: coin,
|
||||
db: db,
|
||||
generateAddressForChain: _generateAddressForChain,
|
||||
cachedElectrumX: cachedElectrumXClient,
|
||||
);
|
||||
initCoinControlInterface(
|
||||
walletId: walletId,
|
||||
|
|
|
@ -8,6 +8,8 @@ import 'package:fusiondart/src/models/input.dart' as fusion_input;
|
|||
import 'package:fusiondart/src/models/transaction.dart' as fusion_tx;
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/db/isar/main_db.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||
import 'package:stackwallet/services/tor_service.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -22,6 +24,7 @@ mixin FusionWalletInterface {
|
|||
late final String _walletId;
|
||||
late final Coin _coin;
|
||||
late final MainDB _db;
|
||||
late final CachedElectrumX _cachedElectrumX;
|
||||
late final TorService _torService;
|
||||
|
||||
// Passed in wallet functions.
|
||||
|
@ -45,6 +48,7 @@ mixin FusionWalletInterface {
|
|||
int,
|
||||
DerivePathType,
|
||||
) generateAddressForChain,
|
||||
required CachedElectrumX cachedElectrumX,
|
||||
}) async {
|
||||
// Set passed in wallet data.
|
||||
_walletId = walletId;
|
||||
|
@ -52,6 +56,7 @@ mixin FusionWalletInterface {
|
|||
_db = db;
|
||||
_generateAddressForChain = generateAddressForChain;
|
||||
_torService = TorService.sharedInstance;
|
||||
_cachedElectrumX = cachedElectrumX;
|
||||
|
||||
// Try getting the proxy info.
|
||||
//
|
||||
|
@ -82,9 +87,11 @@ mixin FusionWalletInterface {
|
|||
String address) async {
|
||||
var _txs = await _db.getTransactions(_walletId).findAll();
|
||||
|
||||
return _txs
|
||||
.map((tx) => tx.toFusionTransaction())
|
||||
.toSet(); // TODO fix public key.
|
||||
// Use Future.wait to await all the futures in the set and then convert it to a set.
|
||||
var resultSet = await Future.wait(
|
||||
_txs.map((tx) => tx.toFusionTransaction(_cachedElectrumX)));
|
||||
|
||||
return resultSet.toSet();
|
||||
}
|
||||
|
||||
/// Returns a list of all UTXOs in the wallet for the given address.
|
||||
|
@ -224,9 +231,45 @@ mixin FusionWalletInterface {
|
|||
|
||||
// Add stack UTXOs.
|
||||
List<UTXO> utxos = await _db.getUTXOs(_walletId).findAll();
|
||||
List<(String, int, int, List<int>)> coinList = [];
|
||||
|
||||
await mainFusionObject.addCoinsFromWallet(
|
||||
utxos.map((e) => (e.txid, e.vout, e.value)).toList());
|
||||
// Loop through UTXOs, checking and adding valid ones.
|
||||
for (var e in utxos) {
|
||||
// Check if address is available.
|
||||
if (e.address == null) {
|
||||
// TODO we could continue here (and below during scriptPubKey validation) instead of throwing.
|
||||
throw Exception("UTXO ${e.txid}:${e.vout} address is null");
|
||||
}
|
||||
|
||||
// Find public key.
|
||||
print("1 getting tx ${e.txid}");
|
||||
Map<String, dynamic> tx = await _cachedElectrumX.getTransaction(coin: _coin,
|
||||
txHash: e.txid, verbose: true); // TODO is verbose needed?
|
||||
|
||||
// Check if scriptPubKey is available.
|
||||
if (tx["vout"] == null) {
|
||||
throw Exception("Vout in transaction ${e.txid} is null");
|
||||
}
|
||||
if (tx["vout"][e.vout] == null) {
|
||||
throw Exception("Vout index ${e.vout} in transaction is null");
|
||||
}
|
||||
if (tx["vout"][e.vout]["scriptPubKey"] == null) {
|
||||
throw Exception("scriptPubKey at vout index ${e.vout} is null");
|
||||
}
|
||||
if (tx["vout"][e.vout]["scriptPubKey"]["hex"] == null) {
|
||||
throw Exception("hex in scriptPubKey at vout index ${e.vout} is null");
|
||||
}
|
||||
|
||||
// Assign scriptPubKey to pubKey. TODO verify this is correct.
|
||||
List<int> pubKey =
|
||||
utf8.encode("${tx["vout"][e.vout]["scriptPubKey"]["hex"]}");
|
||||
|
||||
// Add UTXO to coinList.
|
||||
coinList.add((e.txid, e.vout, e.value, pubKey));
|
||||
}
|
||||
|
||||
// Add Stack UTXOs.
|
||||
await mainFusionObject.addCoinsFromWallet(coinList);
|
||||
|
||||
// Fuse UTXOs.
|
||||
return await mainFusionObject.fuse();
|
||||
|
|
Loading…
Reference in a new issue