Add standalone LNS signature generator for CLI/RPC wallet

This commit is contained in:
Doyle 2020-02-27 16:27:56 +11:00
parent 5dd5723332
commit 68782a76df
8 changed files with 146 additions and 1 deletions

View File

@ -273,6 +273,9 @@ namespace
const char* USAGE_LNS_BUY_MAPPING("lns_buy_mapping [index=<N1>[,<N2>,...]] [<priority>] [owner=] [backup_owner=] \"<name>\" <value>");
const char* USAGE_LNS_UPDATE_MAPPING("lns_update_mapping [index=<N1>[,<N2>,...]] [<priority>] \"<name>\" <value> [<signature>]");
// TODO(loki): Currently defaults to session, in future allow specifying Lokinet and Wallet when they are enabled
const char* USAGE_LNS_MAKE_UPDATE_MAPPING_SIGNATURE("lns_make_update_mapping_signature \"<name>\" <new_value>");
const char* USAGE_LNS_PRINT_OWNERS_TO_NAMES("lns_print_owners_to_names [<64 hex character ed25519 public key>]");
const char* USAGE_LNS_PRINT_NAME_TO_OWNERS("lns_print_name_to_owners [type=<N1|all>[,<N2>...]] \"name\"");
@ -6542,6 +6545,37 @@ bool simple_wallet::lns_update_mapping(const std::vector<std::string>& args)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::lns_make_updating_mapping_signature(const std::vector<std::string> &args)
{
if (!try_connect_to_daemon())
return true;
if (args.size() < 3)
{
PRINT_USAGE(USAGE_LNS_MAKE_UPDATE_MAPPING_SIGNATURE);
return true;
}
std::string const &new_value = args[args.size() - 1];
std::string name;
if (!parse_lns_name_string(args, 0, (args.size() - 2), name))
{
PRINT_USAGE(USAGE_LNS_MAKE_UPDATE_MAPPING_SIGNATURE);
fail_msg_writer() << "lns name didn't start or end with quotation marks (\")";
return true;
}
SCOPED_WALLET_UNLOCK();
crypto::generic_signature signature;
std::string reason;
if (m_wallet->lns_make_update_mapping_signature(lns::mapping_type::session, name, new_value, signature, &reason))
tools::success_msg_writer() << "signature=" << epee::string_tools::pod_to_hex(signature);
else
fail_msg_writer() << reason;
return true;
}
//----------------------------------------------------------------------------------------------------
static char constexpr NULL_KEY_STR[] = "0000000000000000000000000000000000000000000000000000000000000000";
bool simple_wallet::lns_print_name_to_owners(const std::vector<std::string>& args)
{

View File

@ -176,6 +176,7 @@ namespace cryptonote
bool query_locked_stakes(bool print_result);
bool lns_buy_mapping(const std::vector<std::string> &args);
bool lns_update_mapping(const std::vector<std::string> &args);
bool lns_make_updating_mapping_signature(const std::vector<std::string> &args);
bool lns_print_owners_to_names(const std::vector<std::string> &args);
bool lns_print_name_to_owners(const std::vector<std::string> &args);

View File

@ -8692,6 +8692,45 @@ bool wallet2::unlock_keys_file()
return true;
}
bool wallet2::lns_make_update_mapping_signature(lns::mapping_type type, std::string const &name, std::string const &value, crypto::generic_signature &signature, std::string *reason)
{
cryptonote::COMMAND_RPC_LNS_NAMES_TO_OWNERS::request request = {};
request.entries.push_back({name, {static_cast<uint16_t>(type)}});
if (!lns::validate_lns_name(type, name, reason))
return false;
lns::lns_value value_blob;
if (!lns::validate_lns_value(nettype(), type, value, &value_blob, reason))
return false;
boost::optional<std::string> failed;
std::vector<cryptonote::COMMAND_RPC_LNS_NAMES_TO_OWNERS::response_entry> response = lns_names_to_owners(request, failed);
if (failed)
{
if (reason) *reason = *failed;
return false;
}
if (response.empty())
{
if (reason) *reason = "name=\"" + name + std::string("\" does not have a corresponding LNS record, the mapping is available for purchase, update signature is not required.");
return false;
}
cryptonote::COMMAND_RPC_LNS_NAMES_TO_OWNERS::response_entry const &record = response[0];
crypto::hash prev_txid;
if (epee::string_tools::hex_to_pod(response[0].prev_txid, prev_txid))
{
if (reason) *reason = "Failed to convert=" + response[0].prev_txid + std::string(" to a transaction ID.");
return false;
}
crypto::hash hash = lns::tx_extra_signature_hash(epee::span<const uint8_t>(value_blob.buffer.data(), value_blob.len), prev_txid);
crypto::generate_signature(hash, get_account().get_keys().m_account_address.m_spend_public_key, get_account().get_keys().m_spend_secret_key, signature.monero);
return true;
}
bool wallet2::is_keys_file_locked() const
{
return m_keys_file_locker->locked();
@ -8763,7 +8802,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
amount_ss << ask_amount;
oreq.amounts.push_back(amount_ss.str());
}
oreq.count = light_wallet_requested_outputs_count;
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json("/get_random_outs", oreq, ores, rpc_timeout, "POST");

View File

@ -1546,6 +1546,9 @@ private:
std::vector<wallet2::pending_tx> lns_create_update_mapping_tx(lns::mapping_type type, std::string const &name, std::string const &value, std::string const *signature, std::string *reason, uint32_t priority = 0, uint32_t account_index = 0, std::set<uint32_t> subaddr_indices = {});
std::vector<wallet2::pending_tx> lns_create_update_mapping_tx(std::string const &type, std::string const &name, std::string const &value, std::string const *signature, std::string *reason, uint32_t priority = 0, uint32_t account_index = 0, std::set<uint32_t> subaddr_indices = {});
// Generate just the signature required for putting into lns_update_mapping command in the wallet
bool lns_make_update_mapping_signature(lns::mapping_type type, std::string const &name, std::string const &value, crypto::generic_signature &signature, std::string *reason = nullptr);
void freeze(size_t idx);
void thaw(size_t idx);
bool frozen(size_t idx) const;

View File

@ -55,6 +55,7 @@ using namespace epee;
#include "rpc/core_rpc_server_commands_defs.h"
#include "rpc/core_rpc_server.h"
#include "daemonizer/daemonizer.h"
#include "cryptonote_core/loki_name_system.h"
#undef LOKI_DEFAULT_LOG_CATEGORY
#define LOKI_DEFAULT_LOG_CATEGORY "wallet.rpc"
@ -4367,6 +4368,37 @@ namespace tools
res.tx_metadata,
er);
}
bool wallet_rpc_server::on_lns_make_update_mapping_signature(const wallet_rpc::COMMAND_RPC_LNS_MAKE_UPDATE_SIGNATURE::request& req, wallet_rpc::COMMAND_RPC_LNS_MAKE_UPDATE_SIGNATURE::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
if (!m_wallet) return not_open(er);
if (m_restricted)
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Generating the lns update signature is unavailable in restricted mode.";
return false;
}
std::string reason;
lns::mapping_type type;
if (!lns::validate_mapping_type(req.type, &type, &reason))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_LNS_TYPE;
er.message = "Wrong lns type given=" + reason;
return false;
}
crypto::generic_signature signature;
if (!m_wallet->lns_make_update_mapping_signature(type, req.name, req.value, signature, &reason))
{
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
er.message = "Failed to create signature for LNS update transaction: " + reason;
return false;
}
res.signature = epee::string_tools::pod_to_hex(signature);
return true;
}
}
class t_daemon

View File

@ -166,6 +166,7 @@ namespace tools
MAP_JON_RPC_WE("request_stake_unlock", on_request_stake_unlock, wallet_rpc::COMMAND_RPC_REQUEST_STAKE_UNLOCK)
MAP_JON_RPC_WE("lns_buy_mapping", on_lns_buy_mapping, wallet_rpc::COMMAND_RPC_LNS_BUY_MAPPING)
MAP_JON_RPC_WE("lns_update_mapping", on_lns_update_mapping, wallet_rpc::COMMAND_RPC_LNS_UPDATE_MAPPING)
MAP_JON_RPC_WE("lns_make_update_mapping_signature", on_lns_make_update_mapping_signature, wallet_rpc::COMMAND_RPC_LNS_MAKE_UPDATE_SIGNATURE)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -258,6 +259,7 @@ namespace tools
bool on_request_stake_unlock(const wallet_rpc::COMMAND_RPC_REQUEST_STAKE_UNLOCK::request& req, wallet_rpc::COMMAND_RPC_REQUEST_STAKE_UNLOCK::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_lns_buy_mapping(const wallet_rpc::COMMAND_RPC_LNS_BUY_MAPPING::request& req, wallet_rpc::COMMAND_RPC_LNS_BUY_MAPPING::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_lns_update_mapping(const wallet_rpc::COMMAND_RPC_LNS_UPDATE_MAPPING::request& req, wallet_rpc::COMMAND_RPC_LNS_UPDATE_MAPPING::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_lns_make_update_mapping_signature(const wallet_rpc::COMMAND_RPC_LNS_MAKE_UPDATE_SIGNATURE::request& req, wallet_rpc::COMMAND_RPC_LNS_MAKE_UPDATE_SIGNATURE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
//json rpc v2
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);

View File

@ -3038,5 +3038,38 @@ transaction, the open wallet is assumed the owner and it's spend key will automa
typedef epee::misc_utils::struct_init<response_t> response;
};
LOKI_RPC_DOC_INTROSPECT
// Generate the signature necessary for updating the requested record using the wallet's spend key. The signature is
// only valid if the queried wallet is one of the owners of the LNS record.
// This command is only required if the open wallet is one of the owners of a LNS record but want the update
// transaction to occur via another non-owning wallet. By default, if no signature is specified to the update
// transaction, the open wallet is assumed the owner and it's spend key will automatically be used.
struct COMMAND_RPC_LNS_MAKE_UPDATE_SIGNATURE
{
struct request_t
{
std::string type; // The mapping type, currently we only support "session". In future "lokinet" and "blockchain" mappings will be available.
std::string name; // The desired name to update via Loki Name Service
std::string value; // The new value that the name will be updated to via Loki Name Service.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type);
KV_SERIALIZE(name);
KV_SERIALIZE(value);
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::string signature; // A signature valid for using in LNS to update an underlying mapping.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(signature)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
}
}

View File

@ -79,3 +79,4 @@
// Loki:
#define WALLET_RPC_ERROR_CODE_BLINK_FAILED -1000
#define WALLET_RPC_ERROR_CODE_HF_QUERY_FAILED -1001
#define WALLET_RPC_ERROR_CODE_WRONG_LNS_TYPE -1002