mirror of https://github.com/oxen-io/oxen-core.git
wallet RPC: make lns_known_names return record with optional decryption
This saves the GUI wallet, in particular, a lot of work: previously it had to get the values from loki-wallet-rpc, then make a request to lokid to retrieve the records, then for each of those make another call to the wallet-rpc to decrypt the value. This lets lns_known_names do it all in one request.
This commit is contained in:
parent
d3a7a9cef7
commit
e6c2cdaefa
|
@ -3245,12 +3245,14 @@ namespace {
|
|||
require_open();
|
||||
LNS_KNOWN_NAMES::response res{};
|
||||
|
||||
std::vector<lns::mapping_type> entry_types;
|
||||
auto cache = m_wallet->get_lns_cache();
|
||||
res.known_names.reserve(cache.size());
|
||||
entry_types.reserve(cache.size());
|
||||
for (auto& [name, details] : m_wallet->get_lns_cache())
|
||||
{
|
||||
auto& entry = res.known_names.emplace_back();
|
||||
auto type = details.type;
|
||||
auto& type = entry_types.emplace_back(details.type);
|
||||
if (type > lns::mapping_type::lokinet && type <= lns::mapping_type::lokinet_10years)
|
||||
type = lns::mapping_type::lokinet;
|
||||
entry.type = lns::mapping_type_str(type);
|
||||
|
@ -3258,6 +3260,75 @@ namespace {
|
|||
entry.name = details.name;
|
||||
}
|
||||
|
||||
auto nettype = m_wallet->nettype();
|
||||
rpc::LNS_NAMES_TO_OWNERS::request lookup_req{};
|
||||
lookup_req.include_expired = req.include_expired;
|
||||
|
||||
uint64_t curr_height = req.include_expired ? m_wallet->get_blockchain_current_height() : 0;
|
||||
|
||||
// Query lokid for the full record info
|
||||
for (auto it = res.known_names.begin(); it != res.known_names.end(); )
|
||||
{
|
||||
const size_t num_entries = std::distance(it, res.known_names.end());
|
||||
const auto end = num_entries < rpc::LNS_NAMES_TO_OWNERS::MAX_REQUEST_ENTRIES
|
||||
? res.known_names.end()
|
||||
: it + rpc::LNS_NAMES_TO_OWNERS::MAX_REQUEST_ENTRIES;
|
||||
lookup_req.entries.clear();
|
||||
lookup_req.entries.reserve(std::distance(it, end));
|
||||
for (auto it2 = it; it2 != end; it2++)
|
||||
{
|
||||
auto& e = lookup_req.entries.emplace_back();
|
||||
e.name_hash = it2->hashed;
|
||||
e.types.push_back(static_cast<uint16_t>(entry_types[std::distance(res.known_names.begin(), it2)]));
|
||||
}
|
||||
|
||||
if (auto [success, records] = m_wallet->lns_names_to_owners(lookup_req); success)
|
||||
{
|
||||
size_t type_offset = std::distance(res.known_names.begin(), it);
|
||||
for (auto& rec : records)
|
||||
{
|
||||
if (rec.entry_index >= num_entries)
|
||||
{
|
||||
MWARNING("Got back invalid entry_index " << rec.entry_index << " for a request for " << num_entries << " entries");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& res_e = *(it + rec.entry_index);
|
||||
res_e.owner = std::move(rec.owner);
|
||||
res_e.backup_owner = std::move(rec.backup_owner);
|
||||
res_e.encrypted_value = std::move(rec.encrypted_value);
|
||||
res_e.update_height = rec.update_height;
|
||||
res_e.expiration_height = rec.expiration_height;
|
||||
if (req.include_expired && res_e.expiration_height)
|
||||
res_e.expired = *res_e.expiration_height < curr_height;
|
||||
res_e.txid = std::move(rec.txid);
|
||||
|
||||
if (req.decrypt && !res_e.encrypted_value.empty() && lokimq::is_hex(res_e.encrypted_value))
|
||||
{
|
||||
lns::mapping_value value;
|
||||
const auto type = entry_types[type_offset + rec.entry_index];
|
||||
std::string errmsg;
|
||||
if (lns::mapping_value::validate_encrypted(type, lokimq::from_hex(res_e.encrypted_value), &value, &errmsg)
|
||||
&& value.decrypt(res_e.name, type))
|
||||
res_e.value = value.to_readable_value(nettype, type);
|
||||
else
|
||||
MWARNING("Failed to decrypt LNS value for " << res_e.name << (errmsg.empty() ? ""s : ": " + errmsg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it = end;
|
||||
}
|
||||
|
||||
// Erase anything we didn't get a response for (it will have update_height of 0)
|
||||
res.known_names.erase(std::remove_if(res.known_names.begin(), res.known_names.end(),
|
||||
[](const auto& n) { return n.update_height == 0; }),
|
||||
res.known_names.end());
|
||||
|
||||
// Now sort whatever we got back
|
||||
std::sort(res.known_names.begin(), res.known_names.end(),
|
||||
[](const auto& a, const auto& b) { return std::make_pair(a.name, a.type) < std::make_pair(b.name, b.type); });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -1209,10 +1209,24 @@ KV_SERIALIZE_MAP_CODE_BEGIN(LNS_HASH_NAME::response)
|
|||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(LNS_KNOWN_NAMES::known_name)
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(LNS_KNOWN_NAMES::request)
|
||||
KV_SERIALIZE(decrypt)
|
||||
KV_SERIALIZE(include_expired)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(LNS_KNOWN_NAMES::known_record)
|
||||
KV_SERIALIZE(type)
|
||||
KV_SERIALIZE(hashed)
|
||||
KV_SERIALIZE(name)
|
||||
KV_SERIALIZE(owner)
|
||||
KV_SERIALIZE(backup_owner)
|
||||
KV_SERIALIZE(encrypted_value)
|
||||
KV_SERIALIZE(value)
|
||||
KV_SERIALIZE(update_height)
|
||||
KV_SERIALIZE(expiration_height)
|
||||
KV_SERIALIZE(expired)
|
||||
KV_SERIALIZE(txid)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
|
|
|
@ -2361,24 +2361,39 @@ This command is only required if the open wallet is one of the owners of a LNS r
|
|||
};
|
||||
|
||||
LOKI_RPC_DOC_INTROSPECT
|
||||
// Returns a list of known, plain-text LNS names that this wallet knows about.
|
||||
// Returns a list of known, plain-text LNS names along with record details for names that this
|
||||
// wallet knows about. This can optionally decrypt the LNS value as well, or else just return the
|
||||
// encrypted value.
|
||||
struct LNS_KNOWN_NAMES : RPC_COMMAND
|
||||
{
|
||||
static constexpr auto names() { return NAMES("lns_known_names"); }
|
||||
|
||||
struct known_name
|
||||
struct known_record
|
||||
{
|
||||
std::string type; // The mapping type, "session" or "lokinet".
|
||||
std::string hashed; // The hashed name (in base64)
|
||||
std::string name; // The plaintext name
|
||||
std::string type; // The mapping type, "session" or "lokinet".
|
||||
std::string hashed; // The hashed name (in base64)
|
||||
std::string name; // The plaintext name
|
||||
std::string owner; // The public key that purchased the Loki Name Service entry.
|
||||
std::optional<std::string> backup_owner; // The backup public key or wallet that the owner specified when purchasing the Loki Name Service entry. Omitted if no backup owner.
|
||||
std::string encrypted_value; // The encrypted value that the name maps to, in hex.
|
||||
std::optional<std::string> value; // Decrypted value that that name maps to. Only provided if `decrypt: true` was specified in the request.
|
||||
uint64_t update_height; // The last height that this Loki Name Service entry was updated on the Blockchain.
|
||||
std::optional<uint64_t> expiration_height; // For records that expire, this will be set to the expiration block height.
|
||||
std::optional<bool> expired; // Indicates whether the record has expired. Only included in the response if "include_expired" is specified in the request.
|
||||
std::string txid; // The txid of the mapping's most recent update or purchase.
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
struct request {
|
||||
bool decrypt; // If true (default false) then also decrypt and include the `value` field
|
||||
bool include_expired; // If true (default false) then also include expired records
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
struct request : EMPTY {};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::vector<known_name> known_names; // List of (unhashed) name info known to this wallet
|
||||
std::vector<known_record> known_names; // List of records known to this wallet
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue