mirror of
https://github.com/logos-blockchain/logos-blockchain-ui.git
synced 2026-07-09 09:19:26 +00:00
* Modify views * Use structure view for blocks events * Stability fixes * Add cryptarchia info block * Hide settings button on run * Pinnable accounts operation * Use stylish pin button * Show balance on transfer * Stop node on leave * Add info box with peer id * Add vouchers view to leader claim with pending counter * Add help buttons * Remove tx useless label * Update module
168 lines
5.6 KiB
C++
168 lines
5.6 KiB
C++
#include "BlockModel.h"
|
|
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonParseError>
|
|
#include <QJsonValue>
|
|
|
|
namespace {
|
|
|
|
QString prettify(const QJsonValue& value)
|
|
{
|
|
if (value.isObject())
|
|
return QString::fromUtf8(QJsonDocument(value.toObject()).toJson(QJsonDocument::Indented));
|
|
if (value.isArray())
|
|
return QString::fromUtf8(QJsonDocument(value.toArray()).toJson(QJsonDocument::Indented));
|
|
return value.toVariant().toString();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int BlockModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
if (parent.isValid())
|
|
return 0;
|
|
return m_entries.size();
|
|
}
|
|
|
|
QVariant BlockModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
if (!index.isValid() || index.row() < 0 || index.row() >= m_entries.size())
|
|
return QVariant();
|
|
|
|
const Entry& e = m_entries.at(index.row());
|
|
switch (role) {
|
|
case TimestampRole: return e.timestamp;
|
|
case SlotRole: return e.slot;
|
|
case VersionRole: return e.version;
|
|
case ParentBlockRole: return e.parentBlock;
|
|
case BlockRootRole: return e.blockRoot;
|
|
case LeaderKeyRole: return e.leaderKey;
|
|
case EntropyRole: return e.entropy;
|
|
case ProofRole: return e.proof;
|
|
case VoucherCmRole: return e.voucherCm;
|
|
case SignatureRole: return e.signature;
|
|
case TxCountRole: return e.txCount;
|
|
case TransactionsRole: return e.transactions;
|
|
case RawJsonRole: return e.rawJson;
|
|
case ParsedRole: return e.parsed;
|
|
default: return QVariant();
|
|
}
|
|
}
|
|
|
|
QHash<int, QByteArray> BlockModel::roleNames() const
|
|
{
|
|
QHash<int, QByteArray> names;
|
|
names[TimestampRole] = "timestamp";
|
|
names[SlotRole] = "slot";
|
|
names[VersionRole] = "version";
|
|
names[ParentBlockRole] = "parentBlock";
|
|
names[BlockRootRole] = "blockRoot";
|
|
names[LeaderKeyRole] = "leaderKey";
|
|
names[EntropyRole] = "entropy";
|
|
names[ProofRole] = "proof";
|
|
names[VoucherCmRole] = "voucherCm";
|
|
names[SignatureRole] = "signature";
|
|
names[TxCountRole] = "txCount";
|
|
names[TransactionsRole] = "transactions";
|
|
names[RawJsonRole] = "rawJson";
|
|
names[ParsedRole] = "parsed";
|
|
return names;
|
|
}
|
|
|
|
void BlockModel::appendRaw(const QString& timestamp, const QString& rawJson)
|
|
{
|
|
Entry e;
|
|
e.timestamp = timestamp;
|
|
|
|
// The payload is double-encoded JSON: an outer {"block":"<json string>"}
|
|
// whose value is itself a JSON-encoded block. Tolerate a few shapes:
|
|
// { "block": "<stringified block>" } (observed)
|
|
// { "block": { ... } } (already an object)
|
|
// { "header": ..., "transactions": ... }(block sent directly)
|
|
QJsonObject block;
|
|
bool ok = false;
|
|
|
|
QJsonParseError err{};
|
|
const QJsonDocument outer = QJsonDocument::fromJson(rawJson.toUtf8(), &err);
|
|
if (err.error == QJsonParseError::NoError && outer.isObject()) {
|
|
const QJsonObject o = outer.object();
|
|
if (o.contains(QStringLiteral("block"))) {
|
|
const QJsonValue bv = o.value(QStringLiteral("block"));
|
|
if (bv.isString()) {
|
|
const QJsonDocument inner =
|
|
QJsonDocument::fromJson(bv.toString().toUtf8(), &err);
|
|
if (err.error == QJsonParseError::NoError && inner.isObject()) {
|
|
block = inner.object();
|
|
ok = true;
|
|
}
|
|
} else if (bv.isObject()) {
|
|
block = bv.toObject();
|
|
ok = true;
|
|
}
|
|
} else if (o.contains(QStringLiteral("header"))) {
|
|
block = o;
|
|
ok = true;
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
|
e.parsed = true;
|
|
|
|
const QJsonObject header = block.value(QStringLiteral("header")).toObject();
|
|
e.version = header.value(QStringLiteral("version")).toString();
|
|
e.parentBlock = header.value(QStringLiteral("parent_block")).toString();
|
|
|
|
const QJsonValue slotV = header.value(QStringLiteral("slot"));
|
|
e.slot = slotV.isDouble()
|
|
? QString::number(static_cast<qlonglong>(slotV.toDouble()))
|
|
: slotV.toString();
|
|
|
|
e.blockRoot = header.value(QStringLiteral("block_root")).toString();
|
|
|
|
const QJsonObject pol =
|
|
header.value(QStringLiteral("proof_of_leadership")).toObject();
|
|
e.proof = pol.value(QStringLiteral("proof")).toString();
|
|
e.entropy = pol.value(QStringLiteral("entropy_contribution")).toString();
|
|
e.leaderKey = pol.value(QStringLiteral("leader_key")).toString();
|
|
e.voucherCm = pol.value(QStringLiteral("voucher_cm")).toString();
|
|
|
|
e.signature = block.value(QStringLiteral("signature")).toString();
|
|
|
|
const QJsonArray txs = block.value(QStringLiteral("transactions")).toArray();
|
|
e.txCount = txs.size();
|
|
for (const QJsonValue tx : txs)
|
|
e.transactions << prettify(tx);
|
|
|
|
e.rawJson = QString::fromUtf8(QJsonDocument(block).toJson(QJsonDocument::Indented));
|
|
} else {
|
|
// Keep the raw text so an unexpected format is still inspectable.
|
|
e.parsed = false;
|
|
e.rawJson = rawJson;
|
|
}
|
|
|
|
beginInsertRows(QModelIndex(), 0, 0);
|
|
m_entries.prepend(e);
|
|
endInsertRows();
|
|
|
|
if (m_entries.size() > kMaxBlocks) {
|
|
const int last = m_entries.size() - 1;
|
|
beginRemoveRows(QModelIndex(), last, last);
|
|
m_entries.remove(last);
|
|
endRemoveRows();
|
|
}
|
|
|
|
emit countChanged();
|
|
}
|
|
|
|
void BlockModel::clear()
|
|
{
|
|
if (m_entries.isEmpty())
|
|
return;
|
|
beginResetModel();
|
|
m_entries.clear();
|
|
endResetModel();
|
|
emit countChanged();
|
|
}
|