From 968bf390f427f097e6985c53062610312542026b Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 15 Jun 2023 16:39:42 -0600 Subject: [PATCH] fix: eth rescan (and optimise eth txn refreshing) --- .../coins/ethereum/ethereum_wallet.dart | 70 +++++++++++++++---- lib/services/ethereum/ethereum_api.dart | 8 ++- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/lib/services/coins/ethereum/ethereum_wallet.dart b/lib/services/coins/ethereum/ethereum_wallet.dart index 9a6c2dc47..9990406d9 100644 --- a/lib/services/coins/ethereum/ethereum_wallet.dart +++ b/lib/services/coins/ethereum/ethereum_wallet.dart @@ -265,17 +265,23 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { @override Future get fees => EthereumAPI.getFees(); - //Full rescan is not needed for ETH since we have a balance @override Future fullRescan( - int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) { - // TODO: implement fullRescan - throw UnimplementedError(); + int maxUnusedAddressGap, + int maxNumberOfIndexesToCheck, + ) async { + await db.deleteWalletBlockchainData(walletId); + await _generateAndSaveAddress( + (await mnemonicString)!, + (await mnemonicPassphrase)!, + ); + await updateBalance(); + await _refreshTransactions(isRescan: true); } @override Future generateNewAddress() { - // TODO: implement generateNewAddress - might not be needed for ETH + // not used for ETH throw UnimplementedError(); } @@ -291,10 +297,10 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { level: LogLevel.Info, ); - //First get mnemonic so we can initialize credentials - String privateKey = - getPrivateKey((await mnemonicString)!, (await mnemonicPassphrase)!); - _credentials = web3.EthPrivateKey.fromHex(privateKey); + await _initCredentials( + (await mnemonicString)!, + (await mnemonicPassphrase)!, + ); if (getCachedId() == null) { throw Exception( @@ -367,8 +373,24 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { value: "", ); - String privateKey = getPrivateKey(mnemonic, ""); + await _generateAndSaveAddress(mnemonic, ""); + + Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info); + } + + Future _initCredentials( + String mnemonic, + String mnemonicPassphrase, + ) async { + String privateKey = getPrivateKey(mnemonic, mnemonicPassphrase); _credentials = web3.EthPrivateKey.fromHex(privateKey); + } + + Future _generateAndSaveAddress( + String mnemonic, + String mnemonicPassphrase, + ) async { + await _initCredentials(mnemonic, mnemonicPassphrase); final address = Address( walletId: walletId, @@ -381,8 +403,6 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { ); await db.putAddress(address); - - Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info); } bool _isConnected = false; @@ -649,7 +669,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { if (!needsRefresh) { var allOwnAddresses = await _fetchAllOwnAddresses(); final response = await EthereumAPI.getEthTransactions( - allOwnAddresses.elementAt(0).value, + address: allOwnAddresses.elementAt(0).value, ); if (response.value != null) { final allTxs = response.value!; @@ -985,10 +1005,25 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { return isValidEthereumAddress(address); } - Future _refreshTransactions() async { + Future _refreshTransactions({bool isRescan = false}) async { String thisAddress = await currentReceivingAddress; - final response = await EthereumAPI.getEthTransactions(thisAddress); + int firstBlock = 0; + + if (!isRescan) { + firstBlock = + await db.getTransactions(walletId).heightProperty().max() ?? 0; + + if (firstBlock > 10) { + // add some buffer + firstBlock -= 10; + } + } + + final response = await EthereumAPI.getEthTransactions( + address: thisAddress, + firstBlock: isRescan ? 0 : firstBlock, + ); if (response.value == null) { Logging.instance.log( @@ -999,6 +1034,11 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { return; } + if (response.value!.isEmpty) { + // no new transactions found + return; + } + final txsResponse = await EthereumAPI.getEthTransactionNonces(response.value!); diff --git a/lib/services/ethereum/ethereum_api.dart b/lib/services/ethereum/ethereum_api.dart index de4a91540..d30b9ea27 100644 --- a/lib/services/ethereum/ethereum_api.dart +++ b/lib/services/ethereum/ethereum_api.dart @@ -47,12 +47,14 @@ class EthereumResponse { abstract class EthereumAPI { static String get stackBaseServer => DefaultNodes.ethereum.host; - static Future>> getEthTransactions( - String address) async { + static Future>> getEthTransactions({ + required String address, + int firstBlock = 0, + }) async { try { final response = await get( Uri.parse( - "$stackBaseServer/export?addrs=$address", + "$stackBaseServer/export?addrs=$address&firstBlock=$firstBlock", ), );