From 5c2e4fe462de8039f5ffbd5bb21afb91ebdf42ef Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 17 Jul 2026 20:01:49 -0300 Subject: [PATCH] fix(wallet): ignore stale reachability results --- apps/shared/wallet/src/WalletController.cpp | 11 +++-- apps/shared/wallet/src/WalletController.h | 1 + .../tests/cpp/LogosWalletProviderTest.cpp | 44 +++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/apps/shared/wallet/src/WalletController.cpp b/apps/shared/wallet/src/WalletController.cpp index 8694dd3..00db035 100644 --- a/apps/shared/wallet/src/WalletController.cpp +++ b/apps/shared/wallet/src/WalletController.cpp @@ -284,11 +284,16 @@ void WalletController::checkReachability() if (!m_state.isWalletOpen || m_state.sequencerAddress.isEmpty()) return; - QNetworkRequest request{QUrl(m_state.sequencerAddress)}; + const quint64 generation = ++m_reachabilityGeneration; + const QString endpoint = m_state.sequencerAddress; + QNetworkRequest request{QUrl(endpoint)}; request.setTransferTimeout(4000); QNetworkReply* reply = m_network->get(request); - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - if (!m_state.isWalletOpen) { + connect(reply, &QNetworkReply::finished, this, + [this, reply, generation, endpoint]() { + if (!m_state.isWalletOpen + || generation != m_reachabilityGeneration + || endpoint != m_state.sequencerAddress) { reply->deleteLater(); return; } diff --git a/apps/shared/wallet/src/WalletController.h b/apps/shared/wallet/src/WalletController.h index 70caa79..2662a6d 100644 --- a/apps/shared/wallet/src/WalletController.h +++ b/apps/shared/wallet/src/WalletController.h @@ -73,4 +73,5 @@ private: QTimer* m_reachabilityTimer; bool m_started = false; quint64 m_operationGeneration = 0; + quint64 m_reachabilityGeneration = 0; }; diff --git a/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp b/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp index 05573c4..3edfc7f 100644 --- a/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp +++ b/apps/shared/wallet/tests/cpp/LogosWalletProviderTest.cpp @@ -1,9 +1,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -65,6 +68,7 @@ private slots: void controllerStopsReachabilityChecksAfterDisconnect(); void completedAsyncSnapshotReleasesCallback(); void deferredCallbacksIgnoreDestroyedController(); + void newerReachabilityResultWins(); }; void LogosWalletProviderTest::adoptsOpenWalletAndCachesSnapshots() @@ -530,6 +534,46 @@ void LogosWalletProviderTest::deferredCallbacksIgnoreDestroyedController() settings.clear(); } +void LogosWalletProviderTest::newerReachabilityResultWins() +{ + const QString settingsApplication = QStringLiteral("WalletReachabilityOrderTest"); + QSettings settings(QStringLiteral("Logos"), settingsApplication); + settings.clear(); + + QTcpServer server; + QVERIFY(server.listen(QHostAddress::LocalHost)); + const QString endpoint = QStringLiteral("http://127.0.0.1:%1").arg(server.serverPort()); + + FakeWalletProvider provider; + provider.connectResult.snapshot.sequencerAddress = endpoint; + WalletController controller(provider, settingsApplication); + auto* network = controller.findChild(); + QVERIFY(network); + QSignalSpy finished(network, &QNetworkAccessManager::finished); + + QVERIFY(controller.open()); + QTRY_VERIFY(server.hasPendingConnections()); + QTcpSocket* first = server.nextPendingConnection(); + QVERIFY(first); + + provider.createAccountResult.accountId = ACCOUNT_B; + provider.createAccountResult.snapshot.sequencerAddress = endpoint; + QCOMPARE(controller.createAccount(true), ACCOUNT_B); + QTRY_VERIFY(server.hasPendingConnections()); + QTcpSocket* second = server.nextPendingConnection(); + QVERIFY(second); + + second->write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"); + second->disconnectFromHost(); + QTRY_COMPARE(finished.size(), 1); + QVERIFY(controller.state().sequencerReachable); + + first->disconnectFromHost(); + QTRY_COMPARE(finished.size(), 2); + QVERIFY(controller.state().sequencerReachable); + settings.clear(); +} + QTEST_GUILESS_MAIN(LogosWalletProviderTest) #include "LogosWalletProviderTest.moc"