From 892612c084ac34b0904d6deb72d5750d55e5abb7 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Thu, 3 Feb 2022 20:22:25 +0000 Subject: [PATCH] Calculate wallet balances from the transactions (ElectrumX) rather than using bitcoinj. Hopeful fix for incorrect balances in wallets with large numbers of transactions. At the very least, this gives us control of the code that calculates the balance. --- .../api/resource/CrossChainBitcoinResource.java | 13 +++++++++---- .../api/resource/CrossChainDogecoinResource.java | 13 +++++++++---- .../api/resource/CrossChainLitecoinResource.java | 13 +++++++++---- src/main/java/org/qortal/crosschain/Bitcoiny.java | 15 +++++++++++++++ 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java index 9bbf0e43..834c7b81 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java @@ -67,11 +67,16 @@ public class CrossChainBitcoinResource { if (!bitcoin.isValidDeterministicKey(key58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); - Long balance = bitcoin.getWalletBalance(key58); - if (balance == null) - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + try { + Long balance = bitcoin.getWalletBalanceFromTransactions(key58); + if (balance == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); - return balance.toString(); + return balance.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } } @POST diff --git a/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java index bb2dcbbc..189a53d3 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java @@ -65,11 +65,16 @@ public class CrossChainDogecoinResource { if (!dogecoin.isValidDeterministicKey(key58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); - Long balance = dogecoin.getWalletBalance(key58); - if (balance == null) - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + try { + Long balance = dogecoin.getWalletBalanceFromTransactions(key58); + if (balance == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); - return balance.toString(); + return balance.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } } @POST diff --git a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java index 8f6fa582..627c00c7 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java @@ -67,11 +67,16 @@ public class CrossChainLitecoinResource { if (!litecoin.isValidDeterministicKey(key58)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); - Long balance = litecoin.getWalletBalance(key58); - if (balance == null) - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + try { + Long balance = litecoin.getWalletBalanceFromTransactions(key58); + if (balance == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); - return balance.toString(); + return balance.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } } @POST diff --git a/src/main/java/org/qortal/crosschain/Bitcoiny.java b/src/main/java/org/qortal/crosschain/Bitcoiny.java index 3665f4ba..b4cc389b 100644 --- a/src/main/java/org/qortal/crosschain/Bitcoiny.java +++ b/src/main/java/org/qortal/crosschain/Bitcoiny.java @@ -337,6 +337,21 @@ public abstract class Bitcoiny implements ForeignBlockchain { return balance.value; } + public Long getWalletBalanceFromTransactions(String key58) throws ForeignBlockchainException { + long balance = 0; + Comparator oldestTimestampFirstComparator = Comparator.comparingInt(SimpleTransaction::getTimestamp); + List transactions = getWalletTransactions(key58).stream().sorted(oldestTimestampFirstComparator).collect(Collectors.toList()); + for (SimpleTransaction transaction : transactions) { + balance += transaction.getTotalAmount(); + + if (transaction.getTotalAmount() < 0) { + // Outgoing transaction - so this wallet paid the fee + balance -= transaction.getFeeAmount(); + } + } + return balance; + } + public List getWalletTransactions(String key58) throws ForeignBlockchainException { Context.propagate(bitcoinjContext);