Use string_view for address lookups

Also DRY out a bunch of identical address-from-string code blocks.
This commit is contained in:
Jason Rhinelander 2020-06-22 12:43:30 -03:00
parent 5634c46d3d
commit 6f3d3edd0d
7 changed files with 89 additions and 132 deletions

View file

@ -416,8 +416,9 @@ std::vector<std::vector<std::string>> DNSResolver::get_many(int type, const std:
return results;
}
std::string DNSResolver::get_dns_format_from_oa_address(std::string addr)
std::string DNSResolver::get_dns_format_from_oa_address(std::string_view addr_v)
{
std::string addr{addr_v};
auto first_at = addr.find("@");
if (first_at == std::string::npos)
return addr;
@ -454,30 +455,25 @@ namespace dns_utils
//-----------------------------------------------------------------------
// TODO: parse the string in a less stupid way, probably with regex
std::string address_from_txt_record(const std::string& s)
std::string address_from_txt_record(std::string_view s)
{
// make sure the txt record has "oa1:xmr" and find it
auto pos = s.find("oa1:xmr");
if (pos == std::string::npos)
if (auto pos = s.find("oa1:xmr"); pos == std::string_view::npos)
return {};
// search from there to find "recipient_address="
pos = s.find("recipient_address=", pos);
if (pos == std::string::npos)
s.remove_prefix(7); // eat it
if (auto pos = s.find("recipient_address="); pos == std::string_view::npos)
return {};
pos += 18; // move past "recipient_address="
s.remove_prefix(18); // eat it
// find the next semicolon
auto pos2 = s.find(";", pos);
if (pos2 != std::string::npos)
if (auto pos = s.find(";"); pos != std::string::npos)
{
// length of address == 95, we can at least validate that much here
if (pos2 - pos == 95)
{
return s.substr(pos, 95);
}
else if (pos2 - pos == 106) // length of address == 106 --> integrated address
{
return s.substr(pos, 106);
}
if (pos == 95)
return std::string{s.substr(0, 95)};
else if (pos == 106) // length of address == 106 --> integrated address
return std::string{s.substr(0, 106)};
}
return {};
}
@ -495,7 +491,7 @@ std::string address_from_txt_record(const std::string& s)
*
* @return a loki address (as a string) or an empty string
*/
std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec_valid)
std::vector<std::string> addresses_from_url(const std::string_view url, bool& dnssec_valid)
{
std::vector<std::string> addresses;
// get txt records
@ -516,13 +512,14 @@ std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec
std::string addr = address_from_txt_record(rec);
if (addr.size())
{
addresses.push_back(addr);
addresses.push_back(std::move(addr));
}
}
return addresses;
}
std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm)
std::string get_account_address_as_str_from_url(const std::string_view url, bool& dnssec_valid,
std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm)
{
// attempt to get address from dns query
auto addresses = addresses_from_url(url, dnssec_valid);

View file

@ -32,6 +32,7 @@
#include <functional>
#include <optional>
#include <chrono>
#include <string_view>
struct ub_ctx;
@ -133,7 +134,7 @@ public:
*
* @return dns_addr DNS address
*/
std::string get_dns_format_from_oa_address(std::string oa_addr);
std::string get_dns_format_from_oa_address(std::string_view oa_addr);
/**
* @brief Gets the singleton instance of DNSResolver
@ -179,10 +180,11 @@ private:
namespace dns_utils
{
std::string address_from_txt_record(const std::string& s);
std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec_valid);
std::string address_from_txt_record(std::string_view s);
std::vector<std::string> addresses_from_url(const std::string_view url, bool& dnssec_valid);
std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> confirm_dns);
std::string get_account_address_as_str_from_url(const std::string_view url, bool& dnssec_valid,
std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> confirm_dns);
bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls);

View file

@ -202,7 +202,7 @@ namespace cryptonote {
bool get_account_address_from_str(
address_parse_info& info
, network_type nettype
, std::string const & str
, const std::string_view str
)
{
uint64_t address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
@ -268,8 +268,8 @@ namespace cryptonote {
bool get_account_address_from_str_or_url(
address_parse_info& info
, network_type nettype
, const std::string& str_or_url
, std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm
, const std::string_view str_or_url
, std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm
)
{
if (get_account_address_from_str(info, nettype, str_or_url))

View file

@ -94,14 +94,11 @@ namespace cryptonote {
};
#pragma pack (pop)
namespace
inline std::string return_first_address(const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
inline std::string return_first_address(const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
if (addresses.empty())
return {};
return addresses[0];
}
if (addresses.empty())
return {};
return addresses[0];
}
struct address_parse_info
@ -110,6 +107,8 @@ namespace cryptonote {
bool is_subaddress;
bool has_payment_id;
crypto::hash8 payment_id;
std::string as_str(network_type nettype) const;
};
/************************************************************************/
@ -135,17 +134,25 @@ namespace cryptonote {
, const crypto::hash8& payment_id
);
inline std::string address_parse_info::as_str(network_type nettype) const
{
if (has_payment_id)
return get_account_integrated_address_as_str(nettype, address, payment_id);
else
return get_account_address_as_str(nettype, is_subaddress, address);
}
bool get_account_address_from_str(
address_parse_info& info
, network_type nettype
, const std::string& str
, const std::string_view str
);
bool get_account_address_from_str_or_url(
address_parse_info& info
, network_type nettype
, const std::string& str_or_url
, std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm = return_first_address
, const std::string_view str_or_url
, std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm = return_first_address
);
bool is_coinbase(const transaction& tx);

View file

@ -496,7 +496,7 @@ bool command_parser_executor::start_mining(const std::vector<std::string>& args)
{
bool dnssec_valid;
std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(args.front(), dnssec_valid,
[](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid){return addresses[0];});
[](const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid){return addresses[0];});
if(!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, address_str))
{
if(!cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, address_str))

View file

@ -454,7 +454,7 @@ namespace
return "invalid";
}
std::string oa_prompter(const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)
std::string oa_prompter(const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
if (addresses.empty())
return {};

View file

@ -609,6 +609,41 @@ namespace tools
}
return true;
}
static bool extract_account_addr(
cryptonote::address_parse_info& info,
cryptonote::network_type nettype,
std::string_view addr_or_url,
epee::json_rpc::error& er)
{
if (!get_account_address_from_str_or_url(info, nettype, addr_or_url,
[&er](const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid) {
if (!dnssec_valid)
{
er.message = "Invalid DNSSEC for "s;
er.message += url;
return ""s;
}
if (addresses.empty())
{
er.message = "No Loki address found at "s;
er.message += url;
return ""s;
}
return addresses[0];
}))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
if (er.message.empty())
{
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: "s;
er.message += addr_or_url;
}
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::validate_transfer(const std::list<transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er)
{
@ -617,29 +652,11 @@ namespace tools
for (auto it = destinations.begin(); it != destinations.end(); it++)
{
cryptonote::address_parse_info info;
cryptonote::tx_destination_entry de;
er.message = "";
if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), it->address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Loki address found at ") + url;
return {};
}
return addresses[0];
}))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
if (er.message.empty())
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
if (!extract_account_addr(info, m_wallet->nettype(), it->address, er))
return false;
}
cryptonote::tx_destination_entry de;
de.original = it->address;
de.addr = info.address;
de.is_subaddress = info.is_subaddress;
@ -1877,24 +1894,8 @@ namespace tools
cryptonote::address_parse_info info;
er.message = "";
if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), req.address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Loki address found at ") + url;
return {};
}
return addresses[0];
}))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
if (!extract_account_addr(info, m_wallet->nettype(), req.address, er))
return false;
}
res.good = m_wallet->verify(req.data, info.address, req.signature);
return true;
@ -2685,26 +2686,9 @@ namespace tools
cryptonote::address_parse_info info;
er.message = "";
if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), req.address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Loki address found at ") + url;
return {};
}
return addresses[0];
}))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
if (er.message.empty())
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
if (!extract_account_addr(info, m_wallet->nettype(), req.address, er))
return false;
}
if (!m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL, req.description, info.is_subaddress))
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
@ -2739,26 +2723,8 @@ namespace tools
if (req.set_address)
{
er.message = "";
if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), req.address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Monero address found at ") + url;
return {};
}
return addresses[0];
}))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
if (er.message.empty())
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
if (!extract_account_addr(info, m_wallet->nettype(), req.address, er))
return false;
}
entry.m_address = info.address;
entry.m_is_subaddress = info.is_subaddress;
if (info.has_payment_id)
@ -4016,24 +3982,9 @@ namespace tools
continue;
if (req.allow_openalias)
{
std::string address;
res.valid = get_account_address_from_str_or_url(info, net_type.type, req.address,
[&er, &address](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Loki address found at ") + url;
return {};
}
address = addresses[0];
return address;
});
res.valid = extract_account_addr(info, net_type.type, req.address, er);
if (res.valid)
res.openalias_address = address;
res.openalias_address = info.as_str(net_type.type);
}
else
{