mirror of
https://github.com/logos-blockchain/lez-explorer-ui.git
synced 2026-07-30 03:13:25 +00:00
Merge pull request #10 from logos-blockchain/erhant/fix-base58-display
fix: account id now accepts base58
This commit is contained in:
commit
e471eee910
8
flake.lock
generated
8
flake.lock
generated
@ -154,11 +154,11 @@
|
||||
"logos-module-builder": "logos-module-builder_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1782740683,
|
||||
"narHash": "sha256-5FMvtkt9MAzW3mJkJb25uN99PhVr6iH1HaaqzGol1f0=",
|
||||
"lastModified": 1782747538,
|
||||
"narHash": "sha256-Yqups9PRZuoStlehNUYwOnCT59cr43DE2bYS29nHM1g=",
|
||||
"ref": "main",
|
||||
"rev": "78d33cccf7540b628d445b826b63d2d038aa9a1c",
|
||||
"revCount": 54,
|
||||
"rev": "f1c334555d93559330c9e80b9d0a02b4914d8f0a",
|
||||
"revCount": 56,
|
||||
"type": "git",
|
||||
"url": "https://github.com/logos-blockchain/lez-indexer-module"
|
||||
},
|
||||
|
||||
@ -80,6 +80,105 @@ QString jsonStr(const QJsonValue& value)
|
||||
return {};
|
||||
}
|
||||
|
||||
// Account ids are Base58 (matching the wallet UI and canonical LEZ); block/tx
|
||||
// hashes are hex. These mirror the indexer module's codec so the explorer can
|
||||
// recognise an account-shaped query and always display the canonical Base58 form.
|
||||
const char* const kBase58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
int base58Index(char c)
|
||||
{
|
||||
for (int i = 0; i < 58; ++i) {
|
||||
if (kBase58Alphabet[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decode a Base58 string (plain Bitcoin alphabet, no checksum) into raw bytes.
|
||||
// Returns false on any non-Base58 character. Leading '1's map to leading zeros.
|
||||
bool base58Decode(const QString& s, QByteArray& out)
|
||||
{
|
||||
const QString t = s.trimmed();
|
||||
if (t.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
int leadingZeros = 0;
|
||||
for (int i = 0; i < t.size() && t.at(i) == QLatin1Char('1'); ++i) {
|
||||
++leadingZeros;
|
||||
}
|
||||
QByteArray digits; // base-256, least-significant first
|
||||
for (const QChar qc : t) {
|
||||
const int idx = qc.unicode() < 128 ? base58Index(static_cast<char>(qc.unicode())) : -1;
|
||||
if (idx < 0) {
|
||||
return false;
|
||||
}
|
||||
int carry = idx;
|
||||
for (int j = 0; j < digits.size(); ++j) {
|
||||
carry += static_cast<unsigned char>(digits[j]) * 58;
|
||||
digits[j] = static_cast<char>(carry & 0xFF);
|
||||
carry >>= 8;
|
||||
}
|
||||
while (carry > 0) {
|
||||
digits.append(static_cast<char>(carry & 0xFF));
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
out = QByteArray(leadingZeros, '\0');
|
||||
for (int i = digits.size(); i-- > 0;) {
|
||||
out.append(digits[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Base58-encode raw bytes (plain Bitcoin alphabet). Inverse of base58Decode.
|
||||
QString bytes32ToBase58(const QByteArray& data)
|
||||
{
|
||||
int leadingZeros = 0;
|
||||
while (leadingZeros < data.size() && data[leadingZeros] == '\0') {
|
||||
++leadingZeros;
|
||||
}
|
||||
QByteArray digits; // base-58, least-significant first
|
||||
for (int i = 0; i < data.size(); ++i) {
|
||||
int carry = static_cast<unsigned char>(data[i]);
|
||||
for (int j = 0; j < digits.size(); ++j) {
|
||||
carry += static_cast<unsigned char>(digits[j]) * 256;
|
||||
digits[j] = static_cast<char>(carry % 58);
|
||||
carry /= 58;
|
||||
}
|
||||
while (carry > 0) {
|
||||
digits.append(static_cast<char>(carry % 58));
|
||||
carry /= 58;
|
||||
}
|
||||
}
|
||||
QString out(leadingZeros, QLatin1Char('1'));
|
||||
for (int i = digits.size(); i-- > 0;) {
|
||||
out.append(QLatin1Char(kBase58Alphabet[static_cast<unsigned char>(digits[i])]));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Canonical Base58 form of an account-id query, or "" if not account-shaped.
|
||||
// Accepts Base58 (must decode to 32 bytes) or 64-char hex (optionally 0x): a hex
|
||||
// search is normalised to Base58 so the result is displayed in canonical form.
|
||||
QString canonicalAccountId(const QString& query)
|
||||
{
|
||||
const QString trimmed = query.trimmed();
|
||||
QByteArray decoded;
|
||||
if (base58Decode(trimmed, decoded) && decoded.size() == 32) {
|
||||
return trimmed;
|
||||
}
|
||||
QString hex = trimmed;
|
||||
if (hex.startsWith(QStringLiteral("0x"), Qt::CaseInsensitive)) {
|
||||
hex = hex.mid(2);
|
||||
}
|
||||
static const QRegularExpression hexRe(QStringLiteral("^[0-9a-fA-F]{64}$"));
|
||||
if (hexRe.match(hex).hasMatch()) {
|
||||
return bytes32ToBase58(QByteArray::fromHex(hex.toLatin1()));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString timestampText(quint64 timestamp)
|
||||
{
|
||||
QDateTime dt;
|
||||
@ -394,8 +493,14 @@ QVariantMap LezExplorerUiBackend::search(QString query)
|
||||
if (!tx.isEmpty()) {
|
||||
transactions.append(tx);
|
||||
}
|
||||
const QVariantMap account = getAccount(trimmed);
|
||||
// getAccount always injects the id; treat "no payload fields" as miss.
|
||||
}
|
||||
|
||||
// Account ids are Base58 (canonical) or 64-char hex; query and display by
|
||||
// the canonical Base58 form. getAccount injects the id, so a payload with
|
||||
// only that one field means "not found".
|
||||
const QString accountId = canonicalAccountId(trimmed);
|
||||
if (!accountId.isEmpty()) {
|
||||
const QVariantMap account = getAccount(accountId);
|
||||
if (account.size() > 1) {
|
||||
accounts.append(account);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user