mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-07-28 17:53:23 +00:00
fix(amm): refresh wallet holdings on context reload
This commit is contained in:
parent
df5152c5ee
commit
14dff686d1
@ -279,7 +279,7 @@ void NewPositionRuntime::contextAsync(const QVariantMap& request,
|
|||||||
[this, request, network, walletOpen, refreshPublicData,
|
[this, request, network, walletOpen, refreshPublicData,
|
||||||
callback = std::move(callback)](QVector<WalletAccountRead> configReads) mutable {
|
callback = std::move(callback)](QVector<WalletAccountRead> configReads) mutable {
|
||||||
const QJsonObject config = accountReadJson(configReads.value(0));
|
const QJsonObject config = accountReadJson(configReads.value(0));
|
||||||
m_sequencer->readAccounts(m_walletPublicAccountIds, false,
|
m_sequencer->readAccounts(m_walletPublicAccountIds, refreshPublicData,
|
||||||
[this, request, network, walletOpen, refreshPublicData, config,
|
[this, request, network, walletOpen, refreshPublicData, config,
|
||||||
callback = std::move(callback)](
|
callback = std::move(callback)](
|
||||||
QVector<WalletAccountRead> walletReads) mutable {
|
QVector<WalletAccountRead> walletReads) mutable {
|
||||||
|
|||||||
@ -1,8 +1,18 @@
|
|||||||
#include "AmmClient.h"
|
#include "AmmClient.h"
|
||||||
#include "NewPositionRuntime.h"
|
#include "NewPositionRuntime.h"
|
||||||
|
#include "SequencerClient.h"
|
||||||
#include "WalletProvider.h"
|
#include "WalletProvider.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool expect(bool condition, const char* message)
|
bool expect(bool condition, const char* message)
|
||||||
@ -12,6 +22,72 @@ namespace {
|
|||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LocalRpcServer final {
|
||||||
|
public:
|
||||||
|
LocalRpcServer()
|
||||||
|
{
|
||||||
|
QObject::connect(&m_server, &QTcpServer::newConnection, [&]() {
|
||||||
|
while (m_server.hasPendingConnections()) {
|
||||||
|
QTcpSocket* socket = m_server.nextPendingConnection();
|
||||||
|
QObject::connect(socket, &QTcpSocket::readyRead, socket,
|
||||||
|
[this, socket]() { process(socket); });
|
||||||
|
if (socket->bytesAvailable() > 0)
|
||||||
|
process(socket);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool listen()
|
||||||
|
{
|
||||||
|
return m_server.listen(QHostAddress::LocalHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString endpoint() const
|
||||||
|
{
|
||||||
|
return QStringLiteral("http://127.0.0.1:%1").arg(m_server.serverPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
int requestCount() const { return m_requestCount; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process(QTcpSocket* socket)
|
||||||
|
{
|
||||||
|
QByteArray& request = m_requests[socket];
|
||||||
|
request.append(socket->readAll());
|
||||||
|
const qsizetype headerEnd = request.indexOf("\r\n\r\n");
|
||||||
|
if (headerEnd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qsizetype contentLength = 0;
|
||||||
|
for (QByteArray line : request.first(headerEnd).split('\n')) {
|
||||||
|
line = line.trimmed();
|
||||||
|
if (line.toLower().startsWith("content-length:")) {
|
||||||
|
contentLength = line.mid(sizeof("content-length:") - 1)
|
||||||
|
.trimmed().toLongLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const qsizetype bodyStart = headerEnd + 4;
|
||||||
|
if (request.size() - bodyStart < contentLength)
|
||||||
|
return;
|
||||||
|
|
||||||
|
++m_requestCount;
|
||||||
|
const QByteArray payload = QByteArrayLiteral(
|
||||||
|
R"({"jsonrpc":"2.0","id":1,"result":null})");
|
||||||
|
QByteArray response = QByteArrayLiteral(
|
||||||
|
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: ");
|
||||||
|
response += QByteArray::number(payload.size());
|
||||||
|
response += QByteArrayLiteral("\r\nConnection: close\r\n\r\n");
|
||||||
|
response += payload;
|
||||||
|
socket->write(response);
|
||||||
|
socket->disconnectFromHost();
|
||||||
|
m_requests.remove(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTcpServer m_server;
|
||||||
|
QHash<QTcpSocket*, QByteArray> m_requests;
|
||||||
|
int m_requestCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class FakeWallet final : public WalletProvider {
|
class FakeWallet final : public WalletProvider {
|
||||||
public:
|
public:
|
||||||
WalletSession connect(const WalletPaths&) override
|
WalletSession connect(const WalletPaths&) override
|
||||||
@ -80,7 +156,9 @@ namespace {
|
|||||||
public:
|
public:
|
||||||
AmmClientResult configId(const QJsonObject&) const override
|
AmmClientResult configId(const QJsonObject&) const override
|
||||||
{
|
{
|
||||||
return success({ { QStringLiteral("configId"), QStringLiteral("config") } });
|
return success({
|
||||||
|
{ QStringLiteral("configId"), QString(64, QLatin1Char('1')) },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
AmmClientResult tokenIds(const QJsonObject&) const override
|
AmmClientResult tokenIds(const QJsonObject&) const override
|
||||||
@ -136,9 +214,14 @@ namespace {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
AmmClientResult normalizeAccountRpc(const QJsonObject&) const override
|
AmmClientResult normalizeAccountRpc(const QJsonObject& request) const override
|
||||||
{
|
{
|
||||||
return {};
|
return success({
|
||||||
|
{ QStringLiteral("id"),
|
||||||
|
request.value(QStringLiteral("accountId")).toString() },
|
||||||
|
{ QStringLiteral("status"), QStringLiteral("ok") },
|
||||||
|
{ QStringLiteral("account"), QJsonObject() },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static AmmClientResult success(const QJsonObject& value)
|
static AmmClientResult success(const QJsonObject& value)
|
||||||
@ -161,10 +244,29 @@ namespace {
|
|||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool waitForContext(NewPositionRuntime& runtime, bool forceRefresh)
|
||||||
|
{
|
||||||
|
bool completed = false;
|
||||||
|
QEventLoop loop;
|
||||||
|
QTimer timeout;
|
||||||
|
timeout.setSingleShot(true);
|
||||||
|
QObject::connect(&timeout, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||||
|
runtime.contextAsync({}, readyNetwork(), true, forceRefresh,
|
||||||
|
[&](QVariantMap) {
|
||||||
|
completed = true;
|
||||||
|
loop.quit();
|
||||||
|
});
|
||||||
|
timeout.start(3000);
|
||||||
|
if (!completed)
|
||||||
|
loop.exec();
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
QCoreApplication application(argc, argv);
|
||||||
const QVariantMap request {
|
const QVariantMap request {
|
||||||
{ QStringLiteral("schema"), QStringLiteral("new-position.v2") },
|
{ QStringLiteral("schema"), QStringLiteral("new-position.v2") },
|
||||||
{ QStringLiteral("tokenAId"), QStringLiteral("token-a") },
|
{ QStringLiteral("tokenAId"), QStringLiteral("token-a") },
|
||||||
@ -247,5 +349,47 @@ int main()
|
|||||||
"stale quote should have no wallet side effects"))
|
"stale quote should have no wallet side effects"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
LocalRpcServer server;
|
||||||
|
if (!expect(server.listen(), "local sequencer should listen"))
|
||||||
|
return 1;
|
||||||
|
QTemporaryFile sequencerConfig;
|
||||||
|
if (!expect(sequencerConfig.open(), "sequencer config should open"))
|
||||||
|
return 1;
|
||||||
|
sequencerConfig.write(QJsonDocument(QJsonObject {
|
||||||
|
{ QStringLiteral("sequencer_addr"), server.endpoint() },
|
||||||
|
}).toJson(QJsonDocument::Compact));
|
||||||
|
sequencerConfig.flush();
|
||||||
|
|
||||||
|
FakeWallet refreshWallet;
|
||||||
|
FakeAmmClient refreshClient;
|
||||||
|
SequencerClient sequencer(&refreshClient);
|
||||||
|
if (!expect(sequencer.configure(sequencerConfig.fileName()),
|
||||||
|
"sequencer client should configure"))
|
||||||
|
return 1;
|
||||||
|
NewPositionRuntime refreshRuntime(&refreshWallet, &refreshClient, &sequencer);
|
||||||
|
WalletAccount holding;
|
||||||
|
holding.address = QString(64, QLatin1Char('2'));
|
||||||
|
holding.isPublic = true;
|
||||||
|
refreshRuntime.setWalletAccounts({ holding });
|
||||||
|
|
||||||
|
if (!expect(waitForContext(refreshRuntime, false),
|
||||||
|
"initial context should complete"))
|
||||||
|
return 1;
|
||||||
|
if (!expect(server.requestCount() == 2,
|
||||||
|
"initial context should read config and wallet holding"))
|
||||||
|
return 1;
|
||||||
|
if (!expect(waitForContext(refreshRuntime, false),
|
||||||
|
"cached context should complete"))
|
||||||
|
return 1;
|
||||||
|
if (!expect(server.requestCount() == 2,
|
||||||
|
"cached context should not reread accounts"))
|
||||||
|
return 1;
|
||||||
|
if (!expect(waitForContext(refreshRuntime, true),
|
||||||
|
"forced context should complete"))
|
||||||
|
return 1;
|
||||||
|
if (!expect(server.requestCount() == 4,
|
||||||
|
"forced context should reread config and wallet holding"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user