mirror of https://github.com/oxen-io/oxen-core.git
Move RPC for ons resolve address into ons resolve and decrypt wallet side
This commit is contained in:
parent
52ecd26b0d
commit
3030277b6a
|
@ -1911,32 +1911,6 @@ namespace cryptonote
|
|||
return m_blockchain_storage.get_total_transactions();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_account_address_from_str_or_ons(
|
||||
cryptonote::address_parse_info& info
|
||||
, cryptonote::network_type nettype
|
||||
, std::string str,
|
||||
uint64_t height
|
||||
)
|
||||
{
|
||||
bool result = false;
|
||||
if (cryptonote::get_account_address_from_str(info, nettype, str))
|
||||
{
|
||||
result = true;
|
||||
} else {
|
||||
std::string name = tools::lowercase_ascii_string(std::move(str));
|
||||
std::string reason;
|
||||
ons::name_system_db& db = m_blockchain_storage.name_system_db();
|
||||
if (ons::validate_ons_name(ons::mapping_type::wallet, str, &reason) && db.get_wallet_mapping(name, height, info))
|
||||
{
|
||||
result = true;
|
||||
LOG_PRINT_L2("Resolved ONS name: "<< str << " to address: " << get_account_address_as_str(nettype, info.is_subaddress, info.address));
|
||||
} else {
|
||||
LOG_PRINT_L2("Invalid address format, could not resolve " << str);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::relay_txpool_transactions()
|
||||
{
|
||||
// we attempt to relay txes that should be relayed, but were not
|
||||
|
|
|
@ -1042,13 +1042,6 @@ namespace cryptonote
|
|||
*/
|
||||
const fs::path& get_config_directory() const { return m_config_folder; }
|
||||
|
||||
/**
|
||||
* @brief checks if an address is valid, can accept an address or a oxen name service wallet mapping
|
||||
*
|
||||
* @return true if valid address
|
||||
*/
|
||||
bool get_account_address_from_str_or_ons( address_parse_info& info , network_type nettype , std::string str_or_url, uint64_t height);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
@ -869,6 +869,31 @@ bool validate_ons_name(mapping_type type, std::string name, std::string *reason)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::optional<cryptonote::address_parse_info> encrypted_wallet_value_to_info(std::string name, std::string encrypted_value, std::string nonce)
|
||||
{
|
||||
|
||||
std::string lower_name = tools::lowercase_ascii_string(std::move(name));
|
||||
mapping_value record(oxenmq::from_hex(encrypted_value), oxenmq::from_hex(nonce));
|
||||
record.decrypt(lower_name, mapping_type::wallet);
|
||||
|
||||
auto iter = std::next(record.buffer.begin(),1);
|
||||
cryptonote::address_parse_info addr_info{0};
|
||||
addr_info.has_payment_id = false;
|
||||
addr_info.is_subaddress = false;
|
||||
std::memcpy(&addr_info.address.m_spend_public_key.data, &*iter, 32);
|
||||
std::advance(iter,32);
|
||||
std::memcpy(&addr_info.address.m_view_public_key.data, &*iter, 32);
|
||||
if (record.buffer[0] == 0x2) {
|
||||
std::advance(iter,32);
|
||||
std::copy_n(iter,8,addr_info.payment_id.data);
|
||||
addr_info.has_payment_id = true;
|
||||
} else if (record.buffer[0] == 0x1) {
|
||||
addr_info.is_subaddress = true;
|
||||
}
|
||||
|
||||
return addr_info;
|
||||
}
|
||||
|
||||
static bool check_lengths(mapping_type type, std::string_view value, size_t max, bool binary_val, std::string *reason)
|
||||
{
|
||||
bool result;
|
||||
|
@ -1032,6 +1057,17 @@ bool mapping_value::validate_encrypted(mapping_type type, std::string_view value
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
mapping_value::mapping_value(std::string encrypted_value, std::string nonce): buffer{0}
|
||||
{
|
||||
auto it = std::copy(encrypted_value.begin(), encrypted_value.end(), buffer.begin());
|
||||
std::copy(nonce.begin(), nonce.end(), it);
|
||||
len = encrypted_value.size() + nonce.size();
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
mapping_value::mapping_value(){}
|
||||
|
||||
std::string name_hash_bytes_to_base64(std::string_view bytes)
|
||||
{
|
||||
if (bytes.size() != NAME_HASH_SIZE)
|
||||
|
@ -2223,6 +2259,8 @@ bool name_system_db::get_wallet_mapping(std::string str, uint64_t blockchain_hei
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mapping_record name_system_db::get_mapping(mapping_type type, std::string_view name_base64_hash, std::optional<uint64_t> blockchain_height)
|
||||
{
|
||||
assert(name_base64_hash.size() == 44 && name_base64_hash.back() == '=' && oxenmq::is_base64(name_base64_hash));
|
||||
|
|
|
@ -105,6 +105,9 @@ struct mapping_value
|
|||
// blob: (optional) if function returns true then the value will be loaded into the given
|
||||
// mapping_value, ready for decryption via decrypt().
|
||||
static bool validate_encrypted(mapping_type type, std::string_view value, mapping_value *blob = nullptr, std::string *reason = nullptr);
|
||||
|
||||
mapping_value();
|
||||
mapping_value(std::string encrypted_value, std::string nonce);
|
||||
};
|
||||
inline std::ostream &operator<<(std::ostream &os, mapping_value const &v) { return os << oxenmq::to_hex(v.to_view()); }
|
||||
|
||||
|
@ -165,6 +168,8 @@ std::optional<std::string> name_hash_input_to_base64(std::string_view input);
|
|||
|
||||
bool validate_ons_name(mapping_type type, std::string name, std::string *reason = nullptr);
|
||||
|
||||
std::optional<cryptonote::address_parse_info> encrypted_wallet_value_to_info(std::string name, std::string encrypted_value, std::string nonce);
|
||||
|
||||
generic_signature make_ed25519_signature(crypto::hash const &hash, crypto::ed25519_secret_key const &skey);
|
||||
generic_owner make_monero_owner(cryptonote::account_public_address const &owner, bool is_subaddress);
|
||||
generic_owner make_ed25519_owner(crypto::ed25519_public_key const &pkey);
|
||||
|
|
|
@ -3655,6 +3655,7 @@ namespace cryptonote { namespace rpc {
|
|||
if (!name_hash)
|
||||
throw rpc_error{ERROR_WRONG_PARAM, "Unable to resolve ONS address: invalid 'name_hash' value '" + req.name_hash + "'"};
|
||||
|
||||
|
||||
uint8_t hf_version = m_core.get_hard_fork_version(m_core.get_current_blockchain_height());
|
||||
auto type = static_cast<ons::mapping_type>(req.type);
|
||||
if (!ons::mapping_type_allowed(hf_version, type))
|
||||
|
@ -3670,26 +3671,5 @@ namespace cryptonote { namespace rpc {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
ONS_RESOLVE_ADDRESS::response core_rpc_server::invoke(ONS_RESOLVE_ADDRESS::request&& req, rpc_context context)
|
||||
{
|
||||
ONS_RESOLVE_ADDRESS::response res{};
|
||||
|
||||
uint64_t height;
|
||||
height = (req.height) ? req.height : m_core.get_current_blockchain_height();
|
||||
|
||||
cryptonote::address_parse_info info;
|
||||
cryptonote::network_type nettype = m_core.get_nettype();
|
||||
bool success = m_core.get_account_address_from_str_or_ons(info, nettype, req.address, height);
|
||||
|
||||
if (success)
|
||||
{
|
||||
res.status = STATUS_OK;
|
||||
res.address = get_account_address_as_str(nettype, 0, info.address);
|
||||
} else {
|
||||
res.status = "Failed";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} } // namespace cryptonote
|
||||
|
|
|
@ -271,7 +271,6 @@ namespace cryptonote::rpc {
|
|||
ONS_NAMES_TO_OWNERS::response invoke(ONS_NAMES_TO_OWNERS::request&& req, rpc_context context);
|
||||
ONS_OWNERS_TO_NAMES::response invoke(ONS_OWNERS_TO_NAMES::request&& req, rpc_context context);
|
||||
ONS_RESOLVE::response invoke(ONS_RESOLVE::request&& req, rpc_context context);
|
||||
ONS_RESOLVE_ADDRESS::response invoke(ONS_RESOLVE_ADDRESS::request&& req, rpc_context context);
|
||||
FLUSH_CACHE::response invoke(FLUSH_CACHE::request&& req, rpc_context);
|
||||
|
||||
#if defined(OXEN_ENABLE_INTEGRATION_TEST_HOOKS)
|
||||
|
|
|
@ -1340,16 +1340,6 @@ KV_SERIALIZE_MAP_CODE_BEGIN(ONS_NAMES_TO_OWNERS::response)
|
|||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(ONS_RESOLVE_ADDRESS::request)
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(ONS_RESOLVE_ADDRESS::response)
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(ONS_OWNERS_TO_NAMES::request)
|
||||
KV_SERIALIZE(entries)
|
||||
KV_SERIALIZE(include_expired)
|
||||
|
|
|
@ -2481,28 +2481,6 @@ namespace rpc {
|
|||
};
|
||||
};
|
||||
|
||||
// Resolves a provided address, will return the address if valid or the the resolved ONS wallet mapping if valid ONS Name
|
||||
struct ONS_RESOLVE_ADDRESS : PUBLIC
|
||||
{
|
||||
static constexpr auto names() { return NAMES("ons_resolve_address"); }
|
||||
|
||||
struct request
|
||||
{
|
||||
std::string address; // The address or name to resolve to a public key via Oxen Name Service.
|
||||
uint64_t height; // Optional: if provided and true, the result will be provided for a Oxen Name Resolved at this height
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::optional<std::string> address; // The value that the address maps to.
|
||||
std::string status; // Generic RPC error code. "OK" is the success value.
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
};
|
||||
|
||||
OXEN_RPC_DOC_INTROSPECT
|
||||
// Get all the name mappings for the queried owner. The owner can be either a ed25519 public key or Monero style
|
||||
// public key; by default purchases are owned by the spend public key of the purchasing wallet.
|
||||
|
@ -2568,7 +2546,7 @@ namespace rpc {
|
|||
|
||||
struct request
|
||||
{
|
||||
uint16_t type; // The ONS type (mandatory); currently supported values are: 0 = session, 2 = lokinet.
|
||||
uint16_t type; // The ONS type (mandatory); currently supported values are: 0 = session, 1 = wallet, 2 = lokinet.
|
||||
std::string name_hash; // The 32-byte BLAKE2b hash of the name to look up, encoded as 64 hex digits or 44/43 base64 characters (with/without padding).
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
|
@ -2685,7 +2663,6 @@ namespace rpc {
|
|||
ONS_NAMES_TO_OWNERS,
|
||||
ONS_OWNERS_TO_NAMES,
|
||||
ONS_RESOLVE,
|
||||
ONS_RESOLVE_ADDRESS,
|
||||
FLUSH_CACHE
|
||||
>;
|
||||
|
||||
|
|
|
@ -5909,11 +5909,9 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
|
|||
r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[i], oa_prompter);
|
||||
if (!r && m_wallet->is_trusted_daemon())
|
||||
{
|
||||
rpc::ONS_RESOLVE_ADDRESS::request lookup_req{};
|
||||
lookup_req.address = local_args[i];
|
||||
auto [success, addr_response] = m_wallet->resolve_address(lookup_req);
|
||||
if (success)
|
||||
r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), *addr_response.address, oa_prompter);
|
||||
std::optional<std::string> address = m_wallet->resolve_address(local_args[i]);
|
||||
if (address)
|
||||
r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), *address, oa_prompter);
|
||||
}
|
||||
if(!r)
|
||||
{
|
||||
|
|
|
@ -344,10 +344,28 @@ std::pair<bool, std::vector<cryptonote::rpc::ONS_NAMES_TO_OWNERS::response_entry
|
|||
{
|
||||
return get_result_pair<rpc::ONS_NAMES_TO_OWNERS>(request, [](auto&& res) { return std::move(res.entries); });
|
||||
}
|
||||
|
||||
std::pair<bool, cryptonote::rpc::ONS_RESOLVE_ADDRESS::response> NodeRPCProxy::ons_resolve_address(cryptonote::rpc::ONS_RESOLVE_ADDRESS::request const &request) const
|
||||
std::pair<bool,cryptonote::rpc::ONS_RESOLVE::response> NodeRPCProxy::ons_resolve(cryptonote::rpc::ONS_RESOLVE::request const &request) const
|
||||
{
|
||||
return get_result_pair<rpc::ONS_RESOLVE_ADDRESS>(request, [](auto&& res) { return std::move(res); });
|
||||
std::pair<bool, cryptonote::rpc::ONS_RESOLVE::response> result;
|
||||
auto& [success, resolved] = result;
|
||||
success = false;
|
||||
|
||||
uint64_t height;
|
||||
if (m_offline || !get_height(height))
|
||||
return result;
|
||||
|
||||
{
|
||||
try {
|
||||
auto res = m_http_client.json_rpc<rpc::ONS_RESOLVE>(rpc::ONS_RESOLVE::names().front(), request);
|
||||
resolved = res;
|
||||
} catch (...) {
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ public:
|
|||
std::pair<bool, std::vector<cryptonote::rpc::GET_SERVICE_NODE_BLACKLISTED_KEY_IMAGES::entry>> get_service_node_blacklisted_key_images() const;
|
||||
std::pair<bool, std::vector<cryptonote::rpc::ONS_OWNERS_TO_NAMES::response_entry>> ons_owners_to_names(cryptonote::rpc::ONS_OWNERS_TO_NAMES::request const &request) const;
|
||||
std::pair<bool, std::vector<cryptonote::rpc::ONS_NAMES_TO_OWNERS::response_entry>> ons_names_to_owners(cryptonote::rpc::ONS_NAMES_TO_OWNERS::request const &request) const;
|
||||
std::pair<bool, cryptonote::rpc::ONS_RESOLVE_ADDRESS::response> ons_resolve_address(cryptonote::rpc::ONS_RESOLVE_ADDRESS::request const &request) const;
|
||||
std::pair<bool, cryptonote::rpc::ONS_RESOLVE::response>
|
||||
ons_resolve(cryptonote::rpc::ONS_RESOLVE::request const &request) const;
|
||||
|
||||
private:
|
||||
bool get_info() const;
|
||||
|
|
|
@ -6519,6 +6519,45 @@ void wallet2::get_unconfirmed_payments_out(std::list<std::pair<crypto::hash,wall
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::optional<std::string> wallet2::resolve_address(std::string address, uint64_t height)
|
||||
{
|
||||
|
||||
// addr_response will have an encrypted value
|
||||
cryptonote::address_parse_info info;
|
||||
bool result = false;
|
||||
if (cryptonote::get_account_address_from_str(info, m_nettype, address))
|
||||
{
|
||||
result = true;
|
||||
} else {
|
||||
std::string name = tools::lowercase_ascii_string(std::move(address));
|
||||
std::string reason;
|
||||
if (ons::validate_ons_name(ons::mapping_type::wallet, name, &reason))
|
||||
{
|
||||
std::string b64_hashed_name = ons::name_to_base64_hash(name);
|
||||
rpc::ONS_RESOLVE::request lookup_req{1, b64_hashed_name};
|
||||
auto [success, addr_response] = resolve(lookup_req);
|
||||
if (success && addr_response.encrypted_value)
|
||||
{
|
||||
std::optional<cryptonote::address_parse_info> addr_info = ons::encrypted_wallet_value_to_info(name, *addr_response.encrypted_value, *addr_response.nonce);
|
||||
if (addr_info)
|
||||
{
|
||||
info = std::move(*addr_info);
|
||||
result = true;
|
||||
LOG_PRINT_L2("Resolved ONS name: "<< address << " to address: " << get_account_address_as_str(m_nettype, info.is_subaddress, info.address));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_PRINT_L2("Invalid address format, could not resolve " << address);
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
return get_account_address_as_str(m_nettype, info.is_subaddress, info.address);
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2::pool_payment_details>>& unconfirmed_payments, const std::optional<uint32_t>& subaddr_account, const std::set<uint32_t>& subaddr_indices) const
|
||||
{
|
||||
for (auto i = m_unconfirmed_payments.begin(); i != m_unconfirmed_payments.end(); ++i) {
|
||||
|
|
|
@ -806,6 +806,7 @@ private:
|
|||
uint64_t min_height, uint64_t max_height = (uint64_t)-1, const std::optional<uint32_t>& subaddr_account = std::nullopt, const std::set<uint32_t>& subaddr_indices = {}) const;
|
||||
void get_unconfirmed_payments_out(std::list<std::pair<crypto::hash,wallet2::unconfirmed_transfer_details>>& unconfirmed_payments, const std::optional<uint32_t>& subaddr_account = std::nullopt, const std::set<uint32_t>& subaddr_indices = {}) const;
|
||||
void get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2::pool_payment_details>>& unconfirmed_payments, const std::optional<uint32_t>& subaddr_account = std::nullopt, const std::set<uint32_t>& subaddr_indices = {}) const;
|
||||
std::optional<std::string> resolve_address(std::string address, uint64_t height = 0);
|
||||
|
||||
// These return pairs where .first == true if the request was successful, and .second is a
|
||||
// vector of the requested entries.
|
||||
|
@ -817,7 +818,7 @@ private:
|
|||
std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry> list_current_stakes();
|
||||
auto ons_owners_to_names(cryptonote::rpc::ONS_OWNERS_TO_NAMES::request const &request) const { return m_node_rpc_proxy.ons_owners_to_names(request); }
|
||||
auto ons_names_to_owners(cryptonote::rpc::ONS_NAMES_TO_OWNERS::request const &request) const { return m_node_rpc_proxy.ons_names_to_owners(request); }
|
||||
auto resolve_address(cryptonote::rpc::ONS_RESOLVE_ADDRESS::request const &request) const { return m_node_rpc_proxy.ons_resolve_address(request); }
|
||||
auto resolve(cryptonote::rpc::ONS_RESOLVE::request const &request) const { return m_node_rpc_proxy.ons_resolve(request); }
|
||||
|
||||
struct ons_detail
|
||||
{
|
||||
|
|
|
@ -871,14 +871,13 @@ namespace tools
|
|||
cryptonote::network_type nettype,
|
||||
std::string_view addr_or_url)
|
||||
{
|
||||
rpc::ONS_RESOLVE_ADDRESS::request lookup_req{};
|
||||
lookup_req.address = addr_or_url;
|
||||
if (m_wallet->is_trusted_daemon())
|
||||
{
|
||||
if (auto [success, response] = m_wallet->resolve_address(lookup_req); success)
|
||||
std::optional<std::string> address = m_wallet->resolve_address(std::string{addr_or_url});
|
||||
if (address)
|
||||
{
|
||||
cryptonote::address_parse_info info;
|
||||
if (!get_account_address_from_str_or_url(info, nettype, *response.address,
|
||||
if (!get_account_address_from_str_or_url(info, nettype, *address,
|
||||
[](const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid) {
|
||||
if (!dnssec_valid)
|
||||
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid DNSSEC for "s + std::string{url}};
|
||||
|
|
Loading…
Reference in New Issue