Enable ONS mapping type=wallet and resolve ONS wallet addresses

This commit is contained in:
Sean Darcy 2021-02-08 16:31:05 +11:00
parent 944ff226d0
commit 928ad2c668
25 changed files with 586 additions and 332 deletions

View File

@ -1,21 +1,21 @@
// Copyright (c) 2014-2019, The Monero Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -25,7 +25,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <mutex>
@ -158,7 +158,7 @@ namespace crypto {
sc_reduce32(&res);
}
/*
/*
* generate public and secret keys from a random 256-bit integer
*/
secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
@ -377,7 +377,7 @@ namespace crypto {
// pick random k
ec_scalar k = random_scalar();
s_comm_2 buf;
buf.msg = prefix_hash;
buf.D = D;
@ -396,7 +396,7 @@ namespace crypto {
ge_scalarmult_base(&X_p3, &k);
ge_p3_tobytes(&buf.X, &X_p3);
}
// compute Y = k*A
ge_p2 Y_p2;
ge_scalarmult(&Y_p2, &k, &A_p3);

View File

@ -1,21 +1,21 @@
// Copyright (c) 2014-2019, The Monero Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -25,7 +25,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
@ -241,7 +241,7 @@ namespace crypto {
// See above.
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig);
/* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key
/* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key
* derivation D, the signature proves the knowledge of the tx secret key r such that R=r*G and D=r*A
* When the recipient's address is a subaddress, the tx pubkey R is defined as R=r*B where B is the recipient's spend pubkey
*/

View File

@ -1,21 +1,21 @@
// Copyright (c) 2014-2019, The Monero Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -25,7 +25,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once

View File

@ -305,3 +305,10 @@ namespace cryptonote {
return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b);
}
}
KV_SERIALIZE_MAP_CODE_BEGIN(cryptonote::address_parse_info)
KV_SERIALIZE(address)
KV_SERIALIZE(is_subaddress)
KV_SERIALIZE(has_payment_id)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(payment_id)
KV_SERIALIZE_MAP_CODE_END()

View File

@ -1,21 +1,21 @@
// Copyright (c) 2014-2019, The Monero Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -25,7 +25,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
@ -97,6 +97,8 @@ namespace cryptonote {
crypto::hash8 payment_id;
std::string as_str(network_type nettype) const;
KV_MAP_SERIALIZABLE
};
/************************************************************************/

View File

@ -55,6 +55,8 @@ extern "C" {
#include "common/threadpool.h"
#include "common/command_line.h"
#include "common/hex.h"
#include "common/base58.h"
#include "common/dns_utils.h"
#include "epee/warnings.h"
#include "crypto/crypto.h"
#include "cryptonote_config.h"
@ -1343,6 +1345,7 @@ namespace cryptonote
}
}
parse_incoming_tx_accumulated_batch(tx_info, opts.kept_by_block);
return tx_info;
@ -1670,8 +1673,8 @@ namespace cryptonote
crypto::x25519_public_key x_pkey{0};
constexpr std::array<uint16_t, 3> MIN_TIMESTAMP_VERSION{9,0,0};
std::array<uint16_t,3> proofversion;
m_service_node_list.access_proof(pubkey, [&](auto &proof) {
x_pkey = proof.pubkey_x25519;
m_service_node_list.access_proof(pubkey, [&](auto &proof) {
x_pkey = proof.pubkey_x25519;
proofversion = proof.proof->version;
});
@ -1682,7 +1685,7 @@ namespace cryptonote
[this, pubkey](bool success, std::vector<std::string> data) {
const time_t local_seconds = time(nullptr);
MDEBUG("Timestamp message received: " << data[0] <<", local time is: " << local_seconds);
if(success){
if(success){
int64_t received_seconds;
if (tools::parse_int(data[0],received_seconds)){
uint16_t variance;
@ -1694,10 +1697,10 @@ namespace cryptonote
std::lock_guard<std::mutex> lk(m_sn_timestamp_mutex);
// Records the variance into the record of our performance (m_sn_times)
service_nodes::timesync_entry entry{variance <= service_nodes::THRESHOLD_SECONDS_OUT_OF_SYNC};
m_sn_times.add(entry);
m_sn_times.add(entry);
// Counts the number of times we have been out of sync
uint8_t num_sn_out_of_sync = std::count_if(m_sn_times.begin(), m_sn_times.end(),
uint8_t num_sn_out_of_sync = std::count_if(m_sn_times.begin(), m_sn_times.end(),
[](const service_nodes::timesync_entry entry) { return !entry.in_sync; });
if (num_sn_out_of_sync > (m_sn_times.array.size() * service_nodes::MAXIMUM_EXTERNAL_OUT_OF_SYNC/100)) {
MWARNING("service node time might be out of sync");
@ -1908,6 +1911,32 @@ 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

View File

@ -1042,6 +1042,13 @@ 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:
/**

View File

@ -562,6 +562,7 @@ namespace cryptonote
return true;
}
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const std::optional<cryptonote::tx_destination_entry>& change_addr)
{
account_public_address addr = {null_pkey, null_pkey};

View File

@ -130,6 +130,7 @@ namespace cryptonote
// NOTE: Block reward function that should be called after hard fork v10
bool get_oxen_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, int hard_fork_version, block_reward_parts &result, const oxen_block_reward_context &oxen_context);
struct tx_source_entry
{
using output_entry = std::pair<uint64_t, rct::ctkey>;

View File

@ -1,5 +1,8 @@
#include <bitset>
#include <variant>
#include <iterator>
#include <vector>
#include <algorithm>
#include "common/hex.h"
#include "oxen_name_system.h"
@ -106,20 +109,7 @@ std::string lns::mapping_value::to_readable_value(cryptonote::network_type netty
if (is_lokinet_type(type))
{
result = oxenmq::to_base32z(to_view()) + ".loki";
}
else if (type == lns::mapping_type::wallet)
{
cryptonote::address_parse_info addr_info = {};
if (len == sizeof(addr_info))
{
std::memcpy(&addr_info, buffer.data(), len);
result = cryptonote::get_account_address_as_str(nettype, addr_info.is_subaddress, addr_info.address);
}
else
result = "(error unknown wallet address)";
}
else
{
} else {
result = oxenmq::to_hex(to_view());
}
@ -165,11 +155,14 @@ int step(sql_compiled_statement& s)
/// `bind()` binds a particular parameter to a statement by index. The bind type is inferred from
/// the argument.
//TODO sean fix this
// Small (<=32 bits) integers
//template <typename T, std::enable_if_t<std::is_integral_v<T> && (sizeof(T) <= 4), int> = 0>
template <typename T, std::enable_if_t<std::is_integral_v<T> && (sizeof(T) <= 32), int> = 0>
bool bind(sql_compiled_statement& s, int index, const T& val) { return SQLITE_OK == sqlite3_bind_int(s.statement, index, val); }
// Big (>32 bits) integers
//template <typename T, std::enable_if_t<std::is_integral_v<T> && (sizeof(T) > 4), int> = 0>
template <typename T, std::enable_if_t<std::is_integral_v<T> && (sizeof(T) > 32), int> = 0>
bool bind(sql_compiled_statement& s, int index, const T& val) { return SQLITE_OK == sqlite3_bind_int64(s.statement, index, val); }
@ -612,6 +605,8 @@ std::vector<mapping_type> all_mapping_types(uint8_t hf_version) {
result.push_back(mapping_type::session);
if (hf_version >= cryptonote::network_version_16_pulse)
result.push_back(mapping_type::lokinet);
if (hf_version >= cryptonote::network_version_17)
result.push_back(mapping_type::wallet);
return result;
}
@ -846,9 +841,31 @@ bool validate_lns_name(mapping_type type, std::string name, std::string *reason)
reason, "LNS type=", type, ", specifies mapping from name->value where the name contains more than the permitted alphanumeric, underscore or hyphen characters, name=", name))
return false;
}
else if (type == mapping_type::wallet)
{
// WALLET
// Name has to start with a (alphanumeric or underscore), and can have (alphanumeric, hyphens or underscores) in between and must end with a (alphanumeric or underscore)
// ^[a-z0-9_]([a-z0-9-_]*[a-z0-9_])?$
// Must start with (alphanumeric or underscore)
if (check_condition(!char_is_alphanum_or<'_'>(name_view.front()), reason, "ONS type=", type, ", specifies mapping from name->value where the name does not start with an alphanumeric or underscore character, name=", name))
return false;
name_view.remove_prefix(1);
if (!name_view.empty()) {
// Must NOT end with a hyphen '-'
if (check_condition(!char_is_alphanum_or<'_'>(name_view.back()), reason, "ONS type=", type, ", specifies mapping from name->value where the last character is a hyphen '-' which is disallowed, name=", name))
return false;
name_view.remove_suffix(1);
}
// Inbetween start and preceding suffix, (alphanumeric, hyphen or underscore) characters permitted
if (check_condition(!std::all_of(name_view.begin(), name_view.end(), char_is_alphanum_or<'-', '_'>),
reason, "ONS type=", type, ", specifies mapping from name->value where the name contains more than the permitted alphanumeric, underscore or hyphen characters, name=", name))
return false;
}
else
{
MERROR("Wallet names not yet implemented");
MERROR("Type not implemented");
return false;
}
@ -857,7 +874,13 @@ bool validate_lns_name(mapping_type type, std::string name, std::string *reason)
static bool check_lengths(mapping_type type, std::string_view value, size_t max, bool binary_val, std::string *reason)
{
bool result = (value.size() == max);
bool result;
if (type == mapping_type::wallet)
{
result = (value.size() == (WALLET_ACCOUNT_BINARY_LENGTH_INC_PAYMENT_ID + max) || value.size() == (WALLET_ACCOUNT_BINARY_LENGTH_NO_PAYMENT_ID + max));
} else {
result = (value.size() == max);
}
if (!result)
{
if (reason)
@ -873,6 +896,7 @@ static bool check_lengths(mapping_type type, std::string_view value, size_t max,
return result;
}
//This function checks that the value is valid but it also will copy the value into the mapping_value buffer ready for mapping_value::encrypt()
bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type, std::string_view value, mapping_value *blob, std::string *reason)
{
if (blob) *blob = {};
@ -903,8 +927,24 @@ bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type
// Validate blob contents and generate the binary form if possible
if (blob)
{
blob->len = sizeof(addr_info);
std::memcpy(blob->buffer.data(), &addr_info, blob->len);
auto iter = blob->buffer.begin();
uint8_t identifier = 0;
if (addr_info.is_subaddress) {
identifier |= 0x01;
} else if (addr_info.has_payment_id) {
identifier |= 0x02;
}
iter = std::copy_n(&identifier, 1, iter);
iter = std::copy_n(addr_info.address.m_spend_public_key.data, sizeof(addr_info.address.m_spend_public_key.data), iter);
iter = std::copy_n(addr_info.address.m_view_public_key.data, sizeof(addr_info.address.m_view_public_key.data), iter);
size_t counter = 65;
if (addr_info.has_payment_id) {
std::copy_n(addr_info.payment_id.data, sizeof(addr_info.payment_id.data), iter);
counter+=sizeof(addr_info.payment_id);
}
blob->len = counter;
}
}
else if (is_lokinet_type(type))
@ -954,13 +994,20 @@ bool mapping_value::validate_encrypted(mapping_type type, std::string_view value
{
if (blob) *blob = {};
std::stringstream err_stream;
int value_len = crypto_aead_xchacha20poly1305_ietf_ABYTES + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
if (is_lokinet_type(type)) value_len += LOKINET_ADDRESS_BINARY_LENGTH;
else if (type == mapping_type::wallet) value_len += WALLET_ACCOUNT_BINARY_LENGTH;
if (is_lokinet_type(type))
value_len += LOKINET_ADDRESS_BINARY_LENGTH;
else if (type == mapping_type::wallet)
{
value_len = crypto_aead_xchacha20poly1305_ietf_ABYTES + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES; //Add the length in check_length
}
else if (type == mapping_type::session)
{
value_len += SESSION_PUBLIC_KEY_BINARY_LENGTH;
// Allow an HF15 argon2 encrypted value which doesn't contain a nonce:
if (value.size() == value_len - crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
value_len -= crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
@ -1082,6 +1129,25 @@ static bool validate_against_previous_mapping(lns::name_system_db &lns_db, uint6
"Cannot buy an LNS name that is already registered: name_hash=", mapping.name_hash, ", type=", mapping.type,
"; TX: ", tx, "; ", lns_extra_string(lns_db.network_type(), lns_extra)))
return false;
// If buying a new wallet name then the existing session name must not be active and vice versa
// The owner of an existing name but different type is allowed to register but the owner and backup owners
// of the new mapping must be from the same owners and backup owners of the previous mapping ie no
// new addresses are allowed to be added as owner or backup owner.
if (ons_extra.type == mapping_type::wallet)
{
ons::mapping_record session_mapping = ons_db.get_mapping(mapping_type::session, name_hash);
if (check_condition(session_mapping.active(blockchain_height) && (!(session_mapping.owner == ons_extra.owner || session_mapping.backup_owner == ons_extra.owner) || !(!ons_extra.field_is_set(ons::extra_field::backup_owner) || session_mapping.backup_owner == ons_extra.backup_owner || session_mapping.owner == ons_extra.backup_owner)), reason,
"Cannot buy an ONS wallet name that has an already registered session name: name_hash=", mapping.name_hash, ", type=", mapping.type,
"; TX: ", tx, "; ", ons_extra_string(ons_db.network_type(), ons_extra)))
return false;
} else if (ons_extra.type == mapping_type::session) {
ons::mapping_record wallet_mapping = ons_db.get_mapping(mapping_type::wallet, name_hash);
if (check_condition(wallet_mapping.active(blockchain_height) && (!(wallet_mapping.owner == ons_extra.owner || wallet_mapping.backup_owner == ons_extra.owner) || !(!ons_extra.field_is_set(ons::extra_field::backup_owner) || wallet_mapping.backup_owner == ons_extra.backup_owner || wallet_mapping.owner == ons_extra.backup_owner)), reason,
"Cannot buy an ONS session name that has an already registered wallet name: name_hash=", mapping.name_hash, ", type=", mapping.type,
"; TX: ", tx, "; ", ons_extra_string(ons_db.network_type(), ons_extra)))
return false;
}
}
else if (lns_extra.is_renewing())
{
@ -1179,6 +1245,8 @@ bool name_system_db::validate_lns_tx(uint8_t hf_version, uint64_t blockchain_hei
if (!validate_against_previous_mapping(*this, blockchain_height, tx, lns_extra, reason))
return false;
}
// -----------------------------------------------------------------------------------------------
@ -1220,14 +1288,19 @@ bool validate_mapping_type(std::string_view mapping_type_str, uint8_t hf_version
mapping_type_ = lns::mapping_type::lokinet_10years;
}
}
if (hf_version >= cryptonote::network_version_17)
{
if (tools::string_iequal(mapping, "wallet"))
mapping_type_ = lns::mapping_type::wallet;
}
if (!mapping_type_)
{
if (reason) *reason = "Unsupported LNS type \"" + std::string{mapping_type_str} + "\"; supported " + (
txtype == lns_tx_type::update ? "update types are: session, lokinet" :
txtype == lns_tx_type::update ? "update types are: session, lokinet, wallet" :
txtype == lns_tx_type::renew ? "renew types are: lokinet_1y, lokinet_2y, lokinet_5y, lokinet_10y" :
txtype == lns_tx_type::buy ? "buy types are session, lokinet_1y, lokinet_2y, lokinet_5y, lokinet_10y"
: "lookup types are session, lokinet");
: "lookup types are session, lokinet, wallet");
return false;
}
@ -1384,7 +1457,17 @@ bool mapping_value::decrypt(std::string_view name, mapping_type type, const cryp
switch(type) {
case mapping_type::session: dec_length = SESSION_PUBLIC_KEY_BINARY_LENGTH; break;
case mapping_type::lokinet: dec_length = LOKINET_ADDRESS_BINARY_LENGTH; break;
case mapping_type::wallet: dec_length = WALLET_ACCOUNT_BINARY_LENGTH; break;
case mapping_type::wallet: //Wallet type has variable type, check performed in check_length
if (len == WALLET_ACCOUNT_BINARY_LENGTH_INC_PAYMENT_ID + crypto_aead_xchacha20poly1305_ietf_ABYTES + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
{
dec_length = WALLET_ACCOUNT_BINARY_LENGTH_INC_PAYMENT_ID;
} else if (len == WALLET_ACCOUNT_BINARY_LENGTH_NO_PAYMENT_ID + crypto_aead_xchacha20poly1305_ietf_ABYTES + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
{
dec_length = WALLET_ACCOUNT_BINARY_LENGTH_NO_PAYMENT_ID;
} else {
MERROR("Invalid wallet mapping_type length passed to mapping_value::decrypt"); return false;
}
break;
default: MERROR("Invalid mapping_type passed to mapping_value::decrypt"); return false;
}
@ -2118,6 +2201,31 @@ owner_record name_system_db::get_owner_by_id(int64_t owner_id)
return result;
}
bool name_system_db::get_wallet_mapping(std::string str, uint64_t blockchain_height, cryptonote::address_parse_info& addr_info)
{
std::string name = tools::lowercase_ascii_string(std::move(str));
std::string b64_hashed_name = ons::name_to_base64_hash(name);
if (auto record = name_system_db::resolve(mapping_type::wallet, b64_hashed_name, blockchain_height)){
(*record).decrypt(name, mapping_type::wallet);
auto iter = std::next((*record).buffer.begin(),1);
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 true;
}
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));

View File

@ -17,6 +17,7 @@ namespace cryptonote
{
struct checkpoint_t;
struct block;
struct address_parse_info;
class transaction;
struct account_address;
struct tx_extra_oxen_name_system;
@ -26,8 +27,9 @@ class Blockchain;
namespace lns
{
constexpr size_t WALLET_NAME_MAX = 97; // mainnet addresses are 95 but testnet/devnet are 97
constexpr size_t WALLET_ACCOUNT_BINARY_LENGTH = 2 * sizeof(crypto::public_key);
constexpr size_t WALLET_NAME_MAX = 64;
constexpr size_t WALLET_ACCOUNT_BINARY_LENGTH_INC_PAYMENT_ID = 73; // Wallet will encrypt an identifier (1 byte) a public spend and view key (2x 32 bytes) = 65 bytes plus an additional item for payment id (8 bytes) if necessary. The identifier 0 -> No Subaddress or Payment ID, 1 -> Has Subaddress, 2-> Has Payment ID
constexpr size_t WALLET_ACCOUNT_BINARY_LENGTH_NO_PAYMENT_ID = 65;
constexpr size_t LOKINET_DOMAIN_NAME_MAX = 63 + 5; // DNS components name must be at most 63 (+ 5 for .loki); this limit applies if there is at least one hyphen (and thus includes punycode)
constexpr size_t LOKINET_DOMAIN_NAME_MAX_NOHYPHEN = 32 + 5; // If the name does not contain a - then we restrict it to 32 characters so that it cannot be (and is obviously not) an encoded .loki address (52 characters)
constexpr size_t LOKINET_ADDRESS_BINARY_LENGTH = sizeof(crypto::ed25519_public_key);
@ -42,7 +44,7 @@ constexpr size_t SODIUM_ENCRYPTION_EXTRA_BYTES = 40; // crypto_aead_xchacha20pol
struct mapping_value
{
static size_t constexpr BUFFER_SIZE = std::max({WALLET_ACCOUNT_BINARY_LENGTH, LOKINET_ADDRESS_BINARY_LENGTH, SESSION_PUBLIC_KEY_BINARY_LENGTH}) + SODIUM_ENCRYPTION_EXTRA_BYTES;
static size_t constexpr BUFFER_SIZE = std::max({WALLET_ACCOUNT_BINARY_LENGTH_INC_PAYMENT_ID, LOKINET_ADDRESS_BINARY_LENGTH, SESSION_PUBLIC_KEY_BINARY_LENGTH}) + SODIUM_ENCRYPTION_EXTRA_BYTES;
std::array<uint8_t, BUFFER_SIZE> buffer;
bool encrypted;
size_t len;
@ -122,8 +124,9 @@ inline std::string_view mapping_type_str(mapping_type type)
inline std::ostream &operator<<(std::ostream &os, mapping_type type) { return os << mapping_type_str(type); }
constexpr bool mapping_type_allowed(uint8_t hf_version, mapping_type type) {
return (type == mapping_type::session && hf_version >= cryptonote::network_version_15_lns)
|| (is_lokinet_type(type) && hf_version >= cryptonote::network_version_16_pulse);
return (type == mapping_type::session && hf_version >= cryptonote::network_version_15_ons)
|| (is_lokinet_type(type) && hf_version >= cryptonote::network_version_16_pulse)
|| (type == mapping_type::wallet && hf_version >= cryptonote::network_version_17);
}
// Returns all mapping types supported for lookup as of the given hardfork. (Note that this does
@ -280,6 +283,8 @@ struct name_system_db
owner_record get_owner_by_key (generic_owner const &owner);
owner_record get_owner_by_id (int64_t owner_id);
// Returns a wallet address from the passed ONS name in "str"
bool get_wallet_mapping (std::string str, uint64_t blockchain_height, cryptonote::address_parse_info& addr_info);
// The get_mapping* methods can return any mapping, or only active mappings: for only active
// mappings, pass in the blockchain height. If you omit it (or explicitly pass std::nullopt) then
// you will get the latest mappingsvalues regardless of whether expired or not they are expired.

View File

@ -1486,6 +1486,7 @@ namespace cryptonote
{
auto locks = tools::unique_locks(m_transactions_lock, m_blockchain);
bool ret = false;
for(const auto& in: tx.vin)
{

View File

@ -130,7 +130,7 @@ namespace cryptonote { namespace rpc {
template <typename RPC>
struct reg_helper<RPC, std::enable_if_t<std::is_base_of<BINARY, RPC>::value>> {
using Request = typename RPC::request;
Request load(rpc_request& request) {
Request load(rpc_request& request) {
Request req{};
std::string_view data;
if (auto body = request.body_view())
@ -1121,6 +1121,7 @@ namespace cryptonote { namespace rpc {
{
SEND_RAW_TX::response res{};
PERF_TIMER(on_send_raw_tx);
if (use_bootstrap_daemon_if_necessary<SEND_RAW_TX>(req, res))
return res;
@ -1988,7 +1989,7 @@ namespace cryptonote { namespace rpc {
block blk;
bool have_block = m_core.get_block_by_height(h, blk);
if (!have_block)
throw rpc_error{ERROR_INTERNAL,
throw rpc_error{ERROR_INTERNAL,
"Internal error: can't get block by height. Height = " + std::to_string(h) + "."};
if (blk.miner_tx.vin.size() != 1 || !std::holds_alternative<txin_gen>(blk.miner_tx.vin.front()))
throw rpc_error{ERROR_INTERNAL, "Internal error: coinbase transaction in the block has the wrong type"};
@ -3669,5 +3670,26 @@ 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

View File

@ -271,6 +271,7 @@ namespace cryptonote::rpc {
LNS_NAMES_TO_OWNERS::response invoke(LNS_NAMES_TO_OWNERS::request&& req, rpc_context context);
LNS_OWNERS_TO_NAMES::response invoke(LNS_OWNERS_TO_NAMES::request&& req, rpc_context context);
LNS_RESOLVE::response invoke(LNS_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)

View File

@ -1340,6 +1340,15 @@ KV_SERIALIZE_MAP_CODE_BEGIN(LNS_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(LNS_OWNERS_TO_NAMES::request)
KV_SERIALIZE(entries)

View File

@ -2437,7 +2437,7 @@ namespace rpc {
// for Session and Lokinet.
struct LNS_NAMES_TO_OWNERS : PUBLIC
{
static constexpr auto names() { return NAMES("lns_names_to_owners"); }
static constexpr auto names() { return NAMES("ons_names_to_owners", "lns_names_to_owners"); }
static constexpr size_t MAX_REQUEST_ENTRIES = 256;
static constexpr size_t MAX_TYPE_REQUEST_ENTRIES = 8;
@ -2481,12 +2481,34 @@ 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.
struct LNS_OWNERS_TO_NAMES : PUBLIC
{
static constexpr auto names() { return NAMES("lns_owners_to_names"); }
static constexpr auto names() { return NAMES("ons_owners_to_names", "lns_owners_to_names"); }
static constexpr size_t MAX_REQUEST_ENTRIES = 256;
struct request
@ -2542,7 +2564,7 @@ namespace rpc {
// first 24 bytes of the name hash as the public nonce.
struct LNS_RESOLVE : PUBLIC
{
static constexpr auto names() { return NAMES("lns_resolve"); }
static constexpr auto names() { return NAMES("ons_resolve", "lns_resolve"); }
struct request
{
@ -2660,9 +2682,10 @@ namespace rpc {
REPORT_PEER_SS_STATUS,
TEST_TRIGGER_P2P_RESYNC,
TEST_TRIGGER_UPTIME_PROOF,
LNS_NAMES_TO_OWNERS,
LNS_OWNERS_TO_NAMES,
LNS_RESOLVE,
ONS_NAMES_TO_OWNERS,
ONS_OWNERS_TO_NAMES,
ONS_RESOLVE,
ONS_RESOLVE_ADDRESS,
FLUSH_CACHE
>;

View File

@ -1,22 +1,22 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2018-2019, The Loki Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -26,12 +26,12 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
/*!
* \file simplewallet.cpp
*
*
* \brief Source file that defines simple_wallet class.
*/
@ -778,7 +778,7 @@ bool simple_wallet::print_seed(bool encrypted)
else if (m_wallet->is_deterministic())
success = m_wallet->get_seed(seed, seed_pass);
if (success)
if (success)
{
print_seed(seed);
}
@ -856,7 +856,7 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s
}
bool simple_wallet::change_password(const std::vector<std::string> &args)
{
{
const auto orig_pwd_container = get_and_verify_password();
if(!orig_pwd_container)
@ -2211,7 +2211,7 @@ bool simple_wallet::set_store_tx_info(const std::vector<std::string> &args/* = s
fail_msg_writer() << tr("wallet is watch-only and cannot transfer");
return true;
}
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@ -2282,7 +2282,7 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st
{
return true;
}
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@ -3325,7 +3325,7 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
mlog_set_log(args[0].c_str());
}
}
success_msg_writer() << "New log categories: " << mlog_get_categories();
return true;
}
@ -3769,14 +3769,14 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
password = *r;
welcome = true;
}
// Asks user for all the data required to merge secret keys from multisig wallets into one master wallet, which then gets full control of the multisig wallet. The resulting wallet will be the same as any other regular wallet.
else if (!m_generate_from_multisig_keys.empty())
{
m_wallet_file = m_generate_from_multisig_keys;
unsigned int multisig_m;
unsigned int multisig_n;
// parse multisig type
std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1)");
if (std::cin.eof())
@ -3800,9 +3800,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
fail_msg_writer() << tr("Error: M/N is currently unsupported. ");
return false;
}
}
message_writer() << boost::format(tr("Generating master wallet from %u of %u multisig wallet keys")) % multisig_m % multisig_n;
// parse multisig address
std::string address_string = input_line("Multisig wallet address");
if (std::cin.eof())
@ -3817,7 +3817,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("failed to parse address");
return false;
}
// parse secret view key
epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
@ -3833,7 +3833,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("failed to parse secret view key");
return false;
}
// check that the view key matches the given address
crypto::public_key pkey;
if (!crypto::secret_key_to_public_key(viewkey, pkey))
@ -3846,7 +3846,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("view key does not match standard address");
return false;
}
// parse multisig spend keys
crypto::secret_key spendkey;
// parsing N/N
@ -3872,7 +3872,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
}
// sum the spend keys together to get the master spend key
spendkey = multisig_secret_spendkeys[0];
for(unsigned int i=1; i<multisig_n; ++i)
@ -3884,7 +3884,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("Error: M/N is currently unsupported");
return false;
}
// check that the spend key matches the given address
if (!crypto::secret_key_to_public_key(spendkey, pkey))
{
@ -3896,14 +3896,14 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("spend key does not match standard address");
return false;
}
// create wallet
auto r = new_wallet(vm, info.address, spendkey, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
welcome = true;
}
else if (!m_generate_from_json.empty())
{
try
@ -4179,9 +4179,9 @@ bool simple_wallet::try_connect_to_daemon(bool silent, rpc::version_t* version)
/*!
* \brief Gets the word seed language from the user.
*
*
* User is asked to choose from a list of supported languages.
*
*
* \return The chosen language.
*/
std::string simple_wallet::get_mnemonic_language()
@ -4504,7 +4504,7 @@ std::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::pro
fail_msg_writer() << tr("Key file not found. Failed to open wallet");
return {};
}
epee::wipeable_string password;
try
{
@ -5838,9 +5838,9 @@ bool simple_wallet::confirm_and_send_tx(std::vector<cryptonote::address_parse_in
return true;
}
// "transfer [index=<N1>[,<N2>,...]] [<priority>] <address> <amount> [<payment_id>]"
bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std::string> &args_, bool called_by_mms)
{
// "transfer [index=<N1>[,<N2>,...]] [<priority>] <address> <amount> [<payment_id>]"
if (!try_connect_to_daemon())
return false;
@ -5895,34 +5895,32 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
for (size_t i = 0; i < local_args.size(); )
{
dsts_info.emplace_back();
cryptonote::address_parse_info & info = dsts_info.back();
cryptonote::address_parse_info& info = dsts_info.back();
cryptonote::tx_destination_entry de;
bool r = true;
// check for a URI
std::string address_uri, payment_id_uri, tx_description, recipient_name, error;
std::string addr, payment_id_uri, tx_description, recipient_name, error;
std::vector<std::string> unknown_parameters;
uint64_t amount = 0;
bool has_uri = m_wallet->parse_uri(local_args[i], address_uri, payment_id_uri, amount, tx_description, recipient_name, unknown_parameters, error);
if (has_uri)
{
r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), address_uri, oa_prompter);
if (payment_id_uri.size() == 16)
{
if (!tools::hex_to_type(payment_id_uri, info.payment_id))
{
fail_msg_writer() << tr("failed to parse short payment ID from URI");
return false;
}
info.has_payment_id = true;
}
de.amount = amount;
de.original = local_args[i];
++i;
}
else if (i + 1 < local_args.size())
bool has_uri = m_wallet->parse_uri(local_args[i], addr, payment_id_uri, amount, tx_description, recipient_name, unknown_parameters, error);
if (i + 1 < local_args.size())
{
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);
}
if(!r)
{
fail_msg_writer() << tr("Could not resolve address");
return false;
}
bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
if(!ok || 0 == de.amount)
{
@ -5942,11 +5940,7 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
return false;
}
if (!r)
{
fail_msg_writer() << tr("failed to parse address");
return false;
}
de.addr = info.address;
de.is_subaddress = info.is_subaddress;
de.is_integrated = info.has_payment_id;
@ -6013,6 +6007,7 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
return false;
}
oxen_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, txtype::standard, priority);
ptx_vector = m_wallet->create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices, tx_params);
@ -6042,6 +6037,7 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer(const std::vector<std::string> &args_)
{
return transfer_main(Transfer::Normal, args_, false);
}
//----------------------------------------------------------------------------------------------------
@ -6502,6 +6498,7 @@ bool simple_wallet::lns_buy_mapping(std::vector<std::string> args)
SCOPED_WALLET_UNLOCK();
std::string reason;
std::vector<tools::wallet2::pending_tx> ptx_vector;
try
{
ptx_vector = m_wallet->lns_create_buy_mapping_tx(*type,
@ -6513,6 +6510,7 @@ bool simple_wallet::lns_buy_mapping(std::vector<std::string> args)
priority,
m_current_subaddress_account,
subaddr_indices);
if (ptx_vector.empty())
{
tools::fail_msg_writer() << reason;
@ -6528,13 +6526,15 @@ bool simple_wallet::lns_buy_mapping(std::vector<std::string> args)
std::cout << std::endl << tr("Buying Oxen Name System Record") << std::endl << std::endl;
if (*type == lns::mapping_type::session)
std::cout << boost::format(tr("Session Name: %s")) % name << std::endl;
else if (lns::is_lokinet_type(*type))
else if (*type == ons::mapping_type::wallet)
std::cout << boost::format(tr("Wallet Name: %s")) % name << std::endl;
else if (ons::is_lokinet_type(*type))
{
std::cout << boost::format(tr("Lokinet Name: %s")) % name << std::endl;
int years =
*type == lns::mapping_type::lokinet_10years ? 10 :
*type == lns::mapping_type::lokinet_5years ? 5 :
*type == lns::mapping_type::lokinet_2years ? 2 :
int years =
*type == ons::mapping_type::lokinet_10years ? 10 :
*type == ons::mapping_type::lokinet_5years ? 5 :
*type == ons::mapping_type::lokinet_2years ? 2 :
1;
int blocks = BLOCKS_EXPECTED_IN_DAYS(years * lns::REGISTRATION_YEAR_DAYS);
std::cout << boost::format(tr("Registration: %d years (%d blocks)")) % years % blocks << "\n";
@ -6553,9 +6553,9 @@ bool simple_wallet::lns_buy_mapping(std::vector<std::string> args)
return false;
//Save the LNS record to the wallet cache
std::string name_hash_str = lns::name_to_base64_hash(name);
tools::wallet2::lns_detail detail = {
//Save the ONS record to the wallet cache
std::string name_hash_str = ons::name_to_base64_hash(name);
tools::wallet2::ons_detail detail = {
*type,
name,
name_hash_str};
@ -6730,6 +6730,8 @@ bool simple_wallet::lns_update_mapping(std::vector<std::string> args)
std::cout << boost::format(tr("Session Name: %s")) % name << std::endl;
else if (lns::is_lokinet_type(type))
std::cout << boost::format(tr("Lokinet Name: %s")) % name << std::endl;
else if (type == ons::mapping_type::wallet)
std::cout << boost::format(tr("Wallet Name: %s")) % name << std::endl;
else
std::cout << boost::format(tr("Name: %s")) % name << std::endl;
@ -6981,7 +6983,7 @@ bool simple_wallet::lns_print_name_to_owners(std::vector<std::string> args)
writer
<< "\n";
tools::wallet2::lns_detail detail =
tools::wallet2::ons_detail detail =
{
static_cast<lns::mapping_type>(mapping.type),
name,
@ -7024,11 +7026,11 @@ bool simple_wallet::lns_print_owners_to_names(const std::vector<std::string>& ar
fail_msg_writer() << "arg too long, fails basic size sanity check max length = " << MAX_LEN << ", arg = " << arg;
return false;
}
if (!oxenmq::is_hex(arg))
{
fail_msg_writer() << "arg contains non-hex characters: " << arg;
return false;
}
//if (!oxenmq::is_hex(arg))
//{
//fail_msg_writer() << "arg contains non-hex characters: " << arg;
//return false;
//}
if (requests.back().entries.size() >= cryptonote::rpc::LNS_OWNERS_TO_NAMES::MAX_REQUEST_ENTRIES)
requests.emplace_back();
@ -7391,7 +7393,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, Transfer transf
try
{
if (local_args.size() == 1)
if (local_args.size() == 1)
locked_blocks = boost::lexical_cast<uint64_t>(local_args[0]);
else
locked_blocks = boost::lexical_cast<uint64_t>(local_args[1]);
@ -7457,9 +7459,9 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, Transfer transf
std::string addr;
if (local_args.size() > 0)
addr = local_args[0];
else
else
addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0});
if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), addr, oa_prompter))
{
fail_msg_writer() << tr("failed to parse address");
@ -8504,11 +8506,11 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
return true;
rdln::suspend_readline pause_readline;
auto color = epee::console_color_white;
auto formatter = boost::format("%8.8s %6.6s %8.8s %12.12s %16.16s %20.20s %64s %16s %14.14s %s %s - %s");
message_writer(color, true) << formatter
% "Height"
% "Type"
@ -8522,10 +8524,10 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
% "Destination"
% "Subaddress"
% "Note";
for (const auto& transfer : all_transfers)
{
if (transfer.confirmed)
{
switch (transfer.pay_type)
@ -9602,7 +9604,7 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args)
std::string description = m_wallet->get_description();
if (description.empty())
{
description = "<Not set>";
description = "<Not set>";
}
message_writer() << tr("Filename: ") << m_wallet->get_wallet_file();
message_writer() << tr("Description: ") << description;
@ -9829,7 +9831,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
uint64_t spent = 0, unspent = 0;
uint64_t height = m_wallet->import_key_images_from_file(filename, spent, unspent);
success_msg_writer() << "Signed key images imported to height " << height << ", "
<< print_money(spent) << " spent, " << print_money(unspent) << " unspent";
<< print_money(spent) << " spent, " << print_money(unspent) << " unspent";
}
catch (const std::exception &e)
{

View File

@ -1,21 +1,21 @@
// Copyright (c) 2017-2019, The Monero Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -345,4 +345,9 @@ std::pair<bool, std::vector<cryptonote::rpc::LNS_NAMES_TO_OWNERS::response_entry
return get_result_pair<rpc::LNS_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
{
return get_result_pair<rpc::ONS_RESOLVE_ADDRESS>(request, [](auto&& res) { return std::move(res); });
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2017-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
@ -63,6 +62,7 @@ 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::LNS_OWNERS_TO_NAMES::response_entry>> lns_owners_to_names(cryptonote::rpc::LNS_OWNERS_TO_NAMES::request const &request) const;
std::pair<bool, std::vector<cryptonote::rpc::LNS_NAMES_TO_OWNERS::response_entry>> lns_names_to_owners(cryptonote::rpc::LNS_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;
private:
bool get_info() const;

View File

@ -1,22 +1,22 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2018, The Loki Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -26,7 +26,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <iterator>
@ -2621,7 +2621,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
" not match with daemon response size=" + std::to_string(parsed_block.o_indices.indices.size()));
//handle transactions from new block
//optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
if (!should_skip_block(b, height))
{
@ -3377,7 +3377,7 @@ bool wallet2::add_address_book_row(const cryptonote::account_public_address &add
a.m_payment_id = payment_id ? *payment_id : crypto::null_hash8;
a.m_description = description;
a.m_is_subaddress = is_subaddress;
auto old_size = m_address_book.size();
m_address_book.push_back(a);
if(m_address_book.size() == old_size+1)
@ -3404,7 +3404,7 @@ bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_publ
bool wallet2::delete_address_book_row(std::size_t row_id) {
if(m_address_book.size() <= row_id)
return false;
m_address_book.erase(m_address_book.begin()+row_id);
return true;
@ -3506,7 +3506,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
encrypt_keys(*m_encrypt_keys_after_refresh);
m_encrypt_keys_after_refresh = std::nullopt;
}
hwdev.computing_key_images(false);
};
@ -4081,7 +4081,7 @@ std::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::w
std::string original_address;
std::string original_view_secret_key;
if (m_original_keys_available)
{
{
original_address = get_account_address_as_str(m_nettype, false, m_original_address);
value.SetString(original_address.c_str(), original_address.length());
json.AddMember("original_address", value, json.GetAllocator());
@ -4089,7 +4089,7 @@ std::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::w
value.SetString(original_view_secret_key.c_str(), original_view_secret_key.length());
json.AddMember("original_view_secret_key", value, json.GetAllocator());
}
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@ -4409,7 +4409,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_derivation_path, std::string, String, false, std::string());
m_device_derivation_path = field_device_derivation_path;
if (json.HasMember("original_keys_available"))
{
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_keys_available, int, Int, false, false);
@ -5092,7 +5092,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
m_multisig_derivations = derivations;
}
}
if (!m_original_keys_available)
{
// Save the original i.e. non-multisig keys so the MMS can continue to use them to encrypt and decrypt messages
@ -5817,7 +5817,7 @@ void wallet2::load(const fs::path& wallet_, const epee::wipeable_string& passwor
{
MERROR("Failed to save rings, will try again next time");
}
try
{
if (use_fs)
@ -6917,7 +6917,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
// take a pending tx and actually send it to the daemon
void wallet2::commit_tx(pending_tx& ptx, bool blink)
{
if(m_light_wallet)
if(m_light_wallet)
{
light_rpc::SUBMIT_RAW_TX::request oreq{};
light_rpc::SUBMIT_RAW_TX::response ores{};
@ -7015,12 +7015,12 @@ std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) c
unsigned_tx_set txs;
for (auto &tx: ptx_vector)
{
// Short payment id is encrypted with tx_key.
// Short payment id is encrypted with tx_key.
// Since sign_tx() generates new tx_keys and encrypts the payment id, we need to save the decrypted payment ID
// Save tx construction_data to unsigned_tx_set
txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
}
txs.transfers = export_outputs();
// save as binary
std::ostringstream oss;
@ -7119,7 +7119,7 @@ bool wallet2::sign_tx(const fs::path& unsigned_filename, const fs::path& signed_
unsigned_tx_set exported_txs;
if(!load_unsigned_tx(unsigned_filename, exported_txs))
return false;
if (accept_func && !accept_func(exported_txs))
{
LOG_PRINT_L1("Transactions rejected by callback");
@ -8196,7 +8196,7 @@ wallet2::stake_result wallet2::create_stake_tx(const crypto::public_key& service
addr_info.address = this->get_address();
//addr_info.address = this->get_account().get_keys().m_account_address;
//addr_info.is_subaddress = false;
try
{
result = check_stake_allowed(service_node_key, addr_info, amount, amount_fraction);
@ -8706,7 +8706,7 @@ static lns_prepared_args prepare_tx_extra_oxen_name_system_values(wallet2 const
lns_prepared_args result = {};
if (priority == tools::tx_priority_blink)
{
if (reason) *reason = "Can not request a blink TX for Loki Name Service transactions";
if (reason) *reason = "Can not request a blink TX for Oxen Name Service transactions";
return {};
}
@ -9074,14 +9074,14 @@ bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_out
}
void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count) {
MDEBUG("LIGHTWALLET - Getting random outs");
light_rpc::GET_RANDOM_OUTS::request oreq{};
light_rpc::GET_RANDOM_OUTS::response ores{};
size_t light_wallet_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
// Amounts to ask for
// MyMonero api handle amounts and fees as strings
for(size_t idx: selected_transfers) {
@ -9095,7 +9095,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
bool r = invoke_http<light_rpc::GET_RANDOM_OUTS>(oreq, ores);
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
// Check if we got enough outputs for each amount
for(auto& out: ores.amount_outs) {
const uint64_t out_amount = boost::lexical_cast<uint64_t>(out.amount);
@ -9106,32 +9106,32 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
MDEBUG("selected transfers size: " << selected_transfers.size());
for(size_t idx: selected_transfers)
{
{
// Create new index
outs.push_back(std::vector<get_outs_entry>());
outs.back().reserve(fake_outputs_count + 1);
// add real output first
const transfer_details &td = m_transfers[idx];
const uint64_t amount = td.is_rct() ? 0 : td.amount();
outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), rct::commit(td.amount(), td.m_mask)));
MDEBUG("added real output " << tools::type_to_hex(td.get_public_key()));
// Even if the lightwallet server returns random outputs, we pick them randomly.
std::vector<size_t> order;
order.resize(light_wallet_requested_outputs_count);
for (size_t n = 0; n < order.size(); ++n)
order[n] = n;
std::shuffle(order.begin(), order.end(), crypto::random_device{});
LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs with amounts " << print_money(td.is_rct() ? 0 : td.amount()));
MDEBUG("OUTS SIZE: " << outs.back().size());
for (size_t o = 0; o < light_wallet_requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
{
// Random pick
size_t i = order[o];
// Find which random output key to use
bool found_amount = false;
size_t amount_key;
@ -9145,7 +9145,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
THROW_WALLET_EXCEPTION_IF(!found_amount , error::wallet_internal_error, "Outputs for amount " + boost::lexical_cast<std::string>(ores.amount_outs[amount_key].amount) + " not found" );
LOG_PRINT_L2("Index " << i << "/" << light_wallet_requested_outputs_count << ": idx " << ores.amount_outs[amount_key].outputs[i].global_index << " (real " << td.m_global_output_index << "), unlocked " << "(always in light)" << ", key " << ores.amount_outs[0].outputs[i].public_key);
// Convert light wallet string data to proper data structures
crypto::public_key tx_public_key;
rct::key mask{}; // decrypted mask - not used here
@ -9156,7 +9156,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
const uint64_t global_index = ores.amount_outs[amount_key].outputs[i].global_index;
if(!light_wallet_parse_rct_str(ores.amount_outs[amount_key].outputs[i].rct, tx_public_key, 0, mask, rct_commit, false))
rct_commit = rct::zeroCommit(td.amount());
if (tx_add_fake_output(outs, global_index, tx_public_key, rct_commit, td.m_global_output_index, true)) {
MDEBUG("added fake output " << ores.amount_outs[amount_key].outputs[i].public_key);
MDEBUG("index " << global_index);
@ -9164,7 +9164,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
}
THROW_WALLET_EXCEPTION_IF(outs.back().size() < fake_outputs_count + 1 , error::wallet_internal_error, "Not enough fake outputs found" );
// Real output is the first. Shuffle outputs
MTRACE(outs.back().size() << " outputs added. Sorting outputs by index:");
std::sort(outs.back().begin(), outs.back().end(), [](const get_outs_entry &a, const get_outs_entry &b) { return std::get<0>(a) < std::get<0>(b); });
@ -9955,9 +9955,9 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
src.rct = td.is_rct();
//paste mixin transaction
THROW_WALLET_EXCEPTION_IF(outs.size() < out_index + 1 , error::wallet_internal_error, "outs.size() < out_index + 1");
THROW_WALLET_EXCEPTION_IF(outs.size() < out_index + 1 , error::wallet_internal_error, "outs.size() < out_index + 1");
THROW_WALLET_EXCEPTION_IF(outs[out_index].size() < fake_outputs_count , error::wallet_internal_error, "fake_outputs_count > random outputs found");
typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
for (size_t n = 0; n < fake_outputs_count + 1; ++n)
{
@ -10326,7 +10326,7 @@ bool wallet2::light_wallet_login(bool &new_address)
// Always create account if it doesn't exist.
request.create_account = true;
bool connected = invoke_http<light_rpc::LOGIN>(request, response);
// MyMonero doesn't send any status message. OpenMonero does.
// MyMonero doesn't send any status message. OpenMonero does.
m_light_wallet_connected = connected && (response.status.empty() || response.status == "success");
new_address = response.new_address;
MDEBUG("Status: " << response.status);
@ -10358,10 +10358,10 @@ bool wallet2::light_wallet_import_wallet_request(light_rpc::IMPORT_WALLET_REQUES
void wallet2::light_wallet_get_unspent_outs()
{
MDEBUG("Getting unspent outs");
light_rpc::GET_UNSPENT_OUTS::request oreq{};
light_rpc::GET_UNSPENT_OUTS::response ores{};
oreq.amount = "0";
oreq.address = get_account().get_public_address_str(m_nettype);
oreq.view_key = tools::type_to_hex(get_account().get_keys().m_view_secret_key);
@ -10375,22 +10375,22 @@ void wallet2::light_wallet_get_unspent_outs()
bool r = invoke_http<light_rpc::GET_UNSPENT_OUTS>(oreq, ores);
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_unspent_outs");
THROW_WALLET_EXCEPTION_IF(ores.status == "error", error::wallet_internal_error, ores.reason);
m_light_wallet_per_kb_fee = ores.per_kb_fee;
std::unordered_map<crypto::hash,bool> transfers_txs;
for(const auto &t: m_transfers)
transfers_txs.emplace(t.m_txid,t.m_spent);
MDEBUG("FOUND " << ores.outputs.size() <<" outputs");
// return if no outputs found
if(ores.outputs.empty())
return;
// Clear old outputs
m_transfers.clear();
for (const auto &o: ores.outputs) {
bool spent = false;
bool add_transfer = true;
@ -10398,7 +10398,7 @@ void wallet2::light_wallet_get_unspent_outs()
crypto::public_key tx_public_key{};
THROW_WALLET_EXCEPTION_IF(o.tx_pub_key.size() != 64 || !oxenmq::is_hex(o.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
tools::hex_to_type(o.tx_pub_key, tx_public_key);
for (const std::string &ski: o.spend_key_images) {
spent = false;
@ -10414,7 +10414,7 @@ void wallet2::light_wallet_get_unspent_outs()
}
}
// Check if tx already exists in m_transfers.
// Check if tx already exists in m_transfers.
crypto::hash txid;
crypto::public_key tx_pub_key;
crypto::public_key public_key;
@ -10424,7 +10424,7 @@ void wallet2::light_wallet_get_unspent_outs()
tools::hex_to_type(o.tx_hash, txid);
tools::hex_to_type(o.public_key, public_key);
tools::hex_to_type(o.tx_pub_key, tx_pub_key);
for(auto &t: m_transfers){
if(t.get_public_key() == public_key) {
t.m_spent = spent;
@ -10432,20 +10432,20 @@ void wallet2::light_wallet_get_unspent_outs()
break;
}
}
if(!add_transfer)
continue;
m_transfers.emplace_back();
transfer_details& td = m_transfers.back();
td.m_block_height = o.height;
td.m_global_output_index = o.global_index;
td.m_txid = txid;
// Add to extra
add_tx_extra<tx_extra_pub_key>(td.m_tx, tx_pub_key);
td.m_key_image = unspent_key_image;
td.m_key_image_known = !m_watch_only && !m_multisig;
td.m_key_image_request = false;
@ -10459,12 +10459,12 @@ void wallet2::light_wallet_get_unspent_outs()
tx_out txout;
txout.target = txout_to_key(public_key);
txout.amount = td.m_amount;
td.m_tx.vout.resize(td.m_internal_output_index + 1);
td.m_tx.vout[td.m_internal_output_index] = txout;
THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Light wallet multiple output unlock time not supported yet");
// Add unlock time and coinbase bool got from get_address_txs api call
std::unordered_map<crypto::hash,address_tx>::const_iterator found = m_light_wallet_address_txs.find(txid);
THROW_WALLET_EXCEPTION_IF(found == m_light_wallet_address_txs.end(), error::wallet_internal_error, "Lightwallet: tx not found in m_light_wallet_address_txs");
@ -10512,9 +10512,9 @@ void wallet2::light_wallet_get_unspent_outs()
bool wallet2::light_wallet_get_address_info(light_rpc::GET_ADDRESS_INFO::response &response)
{
MTRACE(__FUNCTION__);
light_rpc::GET_ADDRESS_INFO::request request{};
request.address = get_account().get_public_address_str(m_nettype);
request.view_key = tools::type_to_hex(get_account().get_keys().m_view_secret_key);
bool r = invoke_http<light_rpc::GET_ADDRESS_INFO>(request, response);
@ -10526,22 +10526,22 @@ bool wallet2::light_wallet_get_address_info(light_rpc::GET_ADDRESS_INFO::respons
void wallet2::light_wallet_get_address_txs()
{
MDEBUG("Refreshing light wallet");
light_rpc::GET_ADDRESS_TXS::request ireq{};
light_rpc::GET_ADDRESS_TXS::response ires{};
ireq.address = get_account().get_public_address_str(m_nettype);
ireq.view_key = tools::type_to_hex(get_account().get_keys().m_view_secret_key);
bool r = invoke_http<light_rpc::GET_ADDRESS_TXS>(ireq, ires);
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_txs");
//OpenMonero sends status=success, Mymonero doesn't.
//OpenMonero sends status=success, Mymonero doesn't.
THROW_WALLET_EXCEPTION_IF((!ires.status.empty() && ires.status != "success"), error::no_connection_to_daemon, "get_address_txs");
// Abort if no transactions
if(ires.transactions.empty())
return;
// Create searchable vectors
std::vector<crypto::hash> payments_txs;
for(const auto &p: m_payments)
@ -10575,13 +10575,13 @@ void wallet2::light_wallet_get_address_txs()
}
}
// Do not add tx if empty.
// Do not add tx if empty.
if(total_sent == 0 && total_received == 0)
continue;
crypto::hash payment_id = null_hash;
crypto::hash tx_hash;
THROW_WALLET_EXCEPTION_IF(t.payment_id.size() != 64 || !oxenmq::is_hex(t.payment_id), error::wallet_internal_error, "Invalid payment_id field");
THROW_WALLET_EXCEPTION_IF(t.hash.size() != 64 || !oxenmq::is_hex(t.hash), error::wallet_internal_error, "Invalid hash field");
tools::hex_to_type(t.payment_id, payment_id);
@ -10616,8 +10616,8 @@ void wallet2::light_wallet_get_address_txs()
payment.m_unlock_time = t.unlock_time;
payment.m_timestamp = t.timestamp;
payment.m_type = t.coinbase ? wallet::pay_type::miner : wallet::pay_type::in; // TODO(oxen): Only accounts for miner, but wait, do we even care about this code? Looks like openmonero code
if (t.mempool) {
if (t.mempool) {
if (std::find(unconfirmed_payments_txs.begin(), unconfirmed_payments_txs.end(), tx_hash) == unconfirmed_payments_txs.end()) {
pool_txs.push_back(tx_hash);
// assume false as we don't get that info from the light wallet server
@ -10665,8 +10665,8 @@ void wallet2::light_wallet_get_address_txs()
auto confirmed_tx = m_confirmed_txs.find(tx_hash);
if(confirmed_tx == m_confirmed_txs.end()) {
// tx is added to m_unconfirmed_txs - move to confirmed
if(m_unconfirmed_txs.find(tx_hash) != m_unconfirmed_txs.end())
{
if(m_unconfirmed_txs.find(tx_hash) != m_unconfirmed_txs.end())
{
process_unconfirmed(tx_hash, dummy_tx, t.height);
}
// Tx sent by another wallet instance
@ -10684,7 +10684,7 @@ void wallet2::light_wallet_get_address_txs()
if (0 != m_callback)
{
m_callback->on_lw_money_spent(t.height, tx_hash, amount_sent);
}
}
}
// If not new - check the amount and update if necessary.
// when sending a tx to same wallet the receiving amount has to be credited
@ -10699,7 +10699,7 @@ void wallet2::light_wallet_get_address_txs()
}
}
}
}
}
}
// TODO: purge old unconfirmed_txs
remove_obsolete_pool_txs(pool_txs);
@ -10754,7 +10754,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
// Not in cache - calculate key image
crypto::key_image calculated_key_image;
cryptonote::keypair in_ephemeral;
// Subaddresses aren't supported in mymonero/openmonero yet. Roll out the original scheme:
// compute D = a*R
// compute P = Hs(D || i)*G + B
@ -11077,7 +11077,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
unsigned int original_output_index = 0;
std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE);
while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) {
TX &tx = txes.back();
@ -11287,7 +11287,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
skip_tx:
// if unused_*_indices is empty while unused_*_indices_per_subaddr has multiple elements, and if we still have something to pay,
// if unused_*_indices is empty while unused_*_indices_per_subaddr has multiple elements, and if we still have something to pay,
// pop front of unused_*_indices_per_subaddr and have unused_*_indices point to the front of unused_*_indices_per_subaddr
if ((!dsts.empty() && dsts[0].amount > 0) || adding_fee)
{
@ -11687,7 +11687,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) <<
" total fee, " << print_money(accumulated_change) << " total change");
hwdev.set_mode(hw::device::TRANSACTION_CREATE_REAL);
for (auto &tx : txes)
{
@ -12713,7 +12713,7 @@ std::string wallet2::get_reserve_proof(const std::optional<std::pair<uint32_t, u
proof.key_image = td.m_key_image;
subaddr_indices.insert(td.m_subaddr_index);
// get tx pub key
// get tx pub key
const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
@ -13416,7 +13416,7 @@ uint64_t wallet2::import_key_images_from_file(const fs::path& filename, uint64_t
std::memcpy(&pair.first, &data[headerlen + key_image_offset], sizeof(key_image));
std::memcpy(&pair.second, &data[headerlen + signature_offset], sizeof(signature));
}
return import_key_images(ski, offset, spent, unspent);
}
@ -13506,7 +13506,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
}
}
std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
// was created by sweep_all, so we can't know the spent height and other detailed info.
std::unordered_map<crypto::key_image, crypto::hash> spent_key_images;
@ -14543,7 +14543,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
uint64_t timestamp_max = blk_max.timestamp;
if (!(timestamp_min <= timestamp_mid && timestamp_mid <= timestamp_max))
{
// the timestamps are not in the chronological order.
// the timestamps are not in the chronological order.
// assuming they're sufficiently close to each other, simply return the smallest height
return std::min({height_min, height_mid, height_max});
}

View File

@ -817,6 +817,7 @@ private:
std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry> list_current_stakes();
auto lns_owners_to_names(cryptonote::rpc::LNS_OWNERS_TO_NAMES::request const &request) const { return m_node_rpc_proxy.lns_owners_to_names(request); }
auto lns_names_to_owners(cryptonote::rpc::LNS_NAMES_TO_OWNERS::request const &request) const { return m_node_rpc_proxy.lns_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); }
struct lns_detail
{

View File

@ -1,22 +1,22 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2018, The Loki Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -26,7 +26,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <boost/format.hpp>
#include <boost/asio/ip/address.hpp>
@ -866,12 +866,19 @@ namespace tools
return res;
}
static cryptonote::address_parse_info extract_account_addr(
//------------------------------------------------------------------------------------------------------------------------------
cryptonote::address_parse_info wallet_rpc_server::extract_account_addr(
cryptonote::network_type nettype,
std::string_view addr_or_url)
{
cryptonote::address_parse_info info;
if (!get_account_address_from_str_or_url(info, nettype, 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)
{
cryptonote::address_parse_info info;
if (!get_account_address_from_str_or_url(info, nettype, *response.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}};
@ -879,10 +886,26 @@ namespace tools
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "No Oxen address found at "s + std::string{url}};
return addresses[0];
}))
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
return info;
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
return info;
} else {
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
}
} else {
cryptonote::address_parse_info info;
if (!get_account_address_from_str_or_url(info, nettype, addr_or_url,
[](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}};
if (addresses.empty())
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "No Oxen address found at "s + std::string{url}};
return addresses[0];
}))
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
return info;
}
return {};
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::validate_transfer(const std::list<wallet::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)
{
@ -2325,7 +2348,7 @@ namespace tools
if (req.threads_count < 1 || max_mining_threads_count < req.threads_count)
throw wallet_rpc_error{error_code::UNKNOWN_ERROR, "The specified number of threads is inappropriate."};
rpc::START_MINING::request daemon_req{};
rpc::START_MINING::request daemon_req{};
daemon_req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
daemon_req.threads_count = req.threads_count;

View File

@ -184,6 +184,8 @@ namespace tools
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay, bool blink,
Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata);
cryptonote::address_parse_info extract_account_addr(cryptonote::network_type nettype, std::string_view addr_or_url);
void validate_transfer(const std::list<wallet::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);
// Parse options and opens the wallet. Returns nullptr if in directory mode (i.e. no wallet

View File

@ -1,22 +1,22 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2018, The Loki Project
//
//
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -26,7 +26,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
@ -218,7 +218,7 @@ namespace tools::wallet_rpc {
struct request
{
cryptonote::subaddress_index index; // Major & minor address index
cryptonote::subaddress_index index; // Major & minor address index
std::string label; // Label for the address.
KV_MAP_SERIALIZABLE
@ -395,7 +395,7 @@ namespace tools::wallet_rpc {
};
OXEN_RPC_DOC_INTROSPECT
// Send oxen to a number of recipients. To preview the transaction fee, set do_not_relay to true and get_tx_metadata to true.
// Send oxen to a number of recipients. To preview the transaction fee, set do_not_relay to true and get_tx_metadata to true.
// Submit the response using the data in get_tx_metadata in the RPC call, relay_tx.
struct TRANSFER : RESTRICTED
{
@ -500,7 +500,7 @@ namespace tools::wallet_rpc {
uint64_t change_amount; // Change received from transaction in atomic units.
std::string change_address; // Address the change was sent to.
uint64_t fee; // Fee of the transaction in atomic units.
uint32_t dummy_outputs; //
uint32_t dummy_outputs; //
std::string extra; // Data stored in the tx extra represented in hex.
KV_MAP_SERIALIZABLE
@ -587,7 +587,7 @@ namespace tools::wallet_rpc {
struct key_list
{
std::list<std::string> keys;
std::list<std::string> keys;
KV_MAP_SERIALIZABLE
};
@ -599,7 +599,7 @@ namespace tools::wallet_rpc {
std::list<uint64_t> amount_list; // The amount transferred for every transaction.
std::list<uint64_t> fee_list; // The amount of fees paid for every transaction.
std::list<std::string> tx_blob_list; // The tx as hex string for every transaction.
std::list<std::string> tx_metadata_list; // List of transaction metadata needed to relay the transactions later.
std::list<std::string> tx_metadata_list; // List of transaction metadata needed to relay the transactions later.
std::string multisig_txset; // The set of signing keys used in a multisig transaction (empty for non-multisig).
std::string unsigned_txset; // Set of unsigned tx for cold-signing purposes.
@ -620,7 +620,7 @@ namespace tools::wallet_rpc {
std::set<uint32_t> subaddr_indices; // (Optional) Sweep from this set of subaddresses in the account.
bool subaddr_indices_all; //
uint32_t priority; // Set a priority for the transaction. Accepted values are: 1 for unimportant or 5 for blink. (0 and 2-4 are accepted for backwards compatibility and are equivalent to 5)
uint64_t outputs; //
uint64_t outputs; //
uint64_t unlock_time; // Number of blocks before the oxen can be spent (0 to not add a lock).
std::string payment_id; // (Optional) 64-character hex string to identify a transaction.
bool get_tx_keys; // (Optional) Return the transaction keys after sending.
@ -664,7 +664,7 @@ namespace tools::wallet_rpc {
{
std::string address; // Destination public address.
uint32_t priority; // Set a priority for the transaction. Accepted values are: 1 for unimportant or 5 for blink. (0 and 2-4 are accepted for backwards compatibility and are equivalent to 5)
uint64_t outputs; //
uint64_t outputs; //
uint64_t unlock_time; // Number of blocks before the oxen can be spent (0 to not add a lock).
std::string payment_id; // (Optional) 64-character hex string to identify a transaction.
bool get_tx_key; // (Optional) Return the transaction keys after sending.
@ -692,7 +692,7 @@ namespace tools::wallet_rpc {
};
OXEN_RPC_DOC_INTROSPECT
// Relay transaction metadata to the daemon
// Relay transaction metadata to the daemon
struct RELAY_TX : RPC_COMMAND
{
static constexpr auto names() { return NAMES("relay_tx"); }
@ -725,7 +725,7 @@ namespace tools::wallet_rpc {
};
OXEN_RPC_DOC_INTROSPECT
//
//
struct payment_details
{
std::string payment_id; // Payment ID matching the input parameter.
@ -762,11 +762,11 @@ namespace tools::wallet_rpc {
};
OXEN_RPC_DOC_INTROSPECT
// Get a list of incoming payments using a given payment id,
// or a list of payments ids, from a given height.
// Get a list of incoming payments using a given payment id,
// or a list of payments ids, from a given height.
//
// This method is the preferred method over get_paymentsbecause it
// has the same functionality but is more extendable.
// This method is the preferred method over get_paymentsbecause it
// has the same functionality but is more extendable.
// Either is fine for looking up transactions by a single payment ID.
struct GET_BULK_PAYMENTS : RPC_COMMAND
{
@ -782,14 +782,14 @@ namespace tools::wallet_rpc {
struct response
{
std::list<payment_details> payments; // List of payment details:
std::list<payment_details> payments; // List of payment details:
KV_MAP_SERIALIZABLE
};
};
OXEN_RPC_DOC_INTROSPECT
//
//
struct transfer_details
{
uint64_t amount; // Amount of this transfer.
@ -865,7 +865,7 @@ namespace tools::wallet_rpc {
struct response
{
std::string integrated_address; //
std::string integrated_address; //
std::string payment_id; // Hex encoded.
KV_MAP_SERIALIZABLE
@ -880,16 +880,16 @@ namespace tools::wallet_rpc {
struct request
{
std::string integrated_address; //
std::string integrated_address; //
KV_MAP_SERIALIZABLE
};
struct response
{
std::string standard_address; //
std::string payment_id; //
bool is_subaddress; //
std::string standard_address; //
std::string payment_id; //
bool is_subaddress; //
KV_MAP_SERIALIZABLE
};
@ -907,10 +907,10 @@ namespace tools::wallet_rpc {
};
OXEN_RPC_DOC_INTROSPECT
// Rescan the blockchain from scratch, losing any information
// Rescan the blockchain from scratch, losing any information
// which can not be recovered from the blockchain itself.
// This includes destination addresses, tx secret keys, tx notes, etc.
// Warning: This blocks the Wallet RPC executable until rescanning is complete.
struct RESCAN_BLOCKCHAIN : RESTRICTED
{
@ -918,7 +918,7 @@ namespace tools::wallet_rpc {
struct request
{
bool hard; //
bool hard; //
KV_MAP_SERIALIZABLE
};
@ -1187,7 +1187,7 @@ namespace tools::wallet_rpc {
{
bool good; // States if the inputs proves the reserve.
uint64_t total; //
uint64_t spent; //
uint64_t spent; //
KV_MAP_SERIALIZABLE
};
@ -1310,7 +1310,7 @@ namespace tools::wallet_rpc {
struct response
{
bool good; //
bool good; //
KV_MAP_SERIALIZABLE
};
@ -1373,8 +1373,8 @@ namespace tools::wallet_rpc {
struct signed_key_image
{
std::string key_image; //
std::string signature; //
std::string key_image; //
std::string signature; //
KV_MAP_SERIALIZABLE
};
@ -1412,7 +1412,7 @@ namespace tools::wallet_rpc {
struct response
{
uint64_t height;
uint64_t height;
uint64_t spent; // Amount (in atomic units) spent from those key images.
uint64_t unspent; // Amount (in atomic units) still available from those key images.
@ -1464,7 +1464,7 @@ namespace tools::wallet_rpc {
struct response
{
uri_spec uri; // JSON object containing payment information:
std::vector<std::string> unknown_parameters; //
std::vector<std::string> unknown_parameters; //
KV_MAP_SERIALIZABLE
};
@ -1764,7 +1764,7 @@ namespace tools::wallet_rpc {
uint64_t restore_height; // Height in which to start scanning the blockchain for transactions into and out of this Wallet.
std::string filename; // Set the name of the Wallet.
std::string seed; // Mnemonic seed of wallet (25 words).
std::string seed_offset; //
std::string seed_offset; //
std::string password; // Set password for Wallet.
std::string language; // Set language for the wallet.
bool autosave_current; // (Optional: Default true): If a pre-existing wallet is open, save to disk before opening the new wallet.
@ -1777,12 +1777,12 @@ namespace tools::wallet_rpc {
std::string address; // Public address of wallet.
std::string seed; // Seed of wallet.
std::string info; // Wallet information.
bool was_deprecated; //
bool was_deprecated; //
KV_MAP_SERIALIZABLE
};
};
OXEN_RPC_DOC_INTROSPECT
// Check if a wallet is a multisig one.
struct IS_MULTISIG : RPC_COMMAND
@ -1794,7 +1794,7 @@ namespace tools::wallet_rpc {
struct response
{
bool multisig; // States if the wallet is multisig.
bool ready; //
bool ready; //
uint32_t threshold; // Amount of signature needed to sign a transfer.
uint32_t total; // Total amount of signature in the multisig wallet.
@ -1902,7 +1902,7 @@ namespace tools::wallet_rpc {
};
OXEN_RPC_DOC_INTROSPECT
//
//
struct EXCHANGE_MULTISIG_KEYS : RESTRICTED
{
static constexpr auto names() { return NAMES("exchange_multisig_keys"); }
@ -2072,7 +2072,7 @@ namespace tools::wallet_rpc {
KV_MAP_SERIALIZABLE
};
};
OXEN_RPC_DOC_INTROSPECT
// Check if Service Node can unlock its stake.
struct CAN_REQUEST_STAKE_UNLOCK : RESTRICTED
@ -2094,7 +2094,7 @@ namespace tools::wallet_rpc {
KV_MAP_SERIALIZABLE
};
};
OXEN_RPC_DOC_INTROSPECT
// Parse an address to validate if it's a valid Loki address.
struct VALIDATE_ADDRESS : RPC_COMMAND
@ -2104,8 +2104,8 @@ namespace tools::wallet_rpc {
struct request
{
std::string address; // Address to check.
bool any_net_type; //
bool allow_openalias; //
bool any_net_type; //
bool allow_openalias; //
KV_MAP_SERIALIZABLE
};
@ -2186,7 +2186,7 @@ namespace tools::wallet_rpc {
static constexpr const char *description =
R"(Buy a Loki Name System (LNS) mapping that maps a unique name to a Session ID or Lokinet address.
Currently supports Session and Lokinet registrations. Lokinet registrations can be for 1, 2, 5, or 10 years by specifying a type value of "lokinet", "lokinet_2y", "lokinet_5y", "lokinet_10y". Session registrations do not expire.
Currently supports Session, Lokinet and Wallet registrations. Lokinet registrations can be for 1, 2, 5, or 10 years by specifying a type value of "lokinet", "lokinet_2y", "lokinet_5y", "lokinet_10y". Session registrations do not expire.
The owner of the LNS entry (by default, the purchasing wallet) will be permitted to submit LNS update transactions to the Loki blockchain (for example to update a Session pubkey or the target Lokinet address). You may change the primary owner or add a backup owner in the registration and can change them later with update transactions. Owner addresses can be either Loki wallets, or generic ed25519 pubkeys (for advanced uses).
@ -2198,11 +2198,11 @@ For more information on updating and signing see the LNS_UPDATE_MAPPING document
struct request
{
std::string type; // The mapping type: "session", "lokinet", "lokinet_2y", "lokinet_5y", "lokinet_10y".
std::string type; // The mapping type: "session", "lokinet", "lokinet_2y", "lokinet_5y", "lokinet_10y", "wallet".
std::string owner; // (Optional): The ed25519 public key or wallet address that has authority to update the mapping.
std::string backup_owner; // (Optional): The secondary, backup public key that has authority to update the mapping.
std::string name; // The name to purchase via Loki Name Service
std::string value; // The value that the name maps to via Loki Name Service, (i.e. For Session: [display name->session public key]. In future, for wallets: [name->wallet address], for Lokinet: [name->domain name]).
std::string name; // The name to purchase via Oxen Name Service
std::string value; // The value that the name maps to via Oxen Name Service, (i.e. For Session: [display name->session public key], for wallets: [name->wallet address], for Lokinet: [name->domain name]).
uint32_t account_index; // (Optional) Transfer from this account index. (Defaults to 0)
std::set<uint32_t> subaddr_indices; // (Optional) Transfer from this set of subaddresses. (Defaults to 0)
@ -2277,7 +2277,7 @@ If signing is performed externally then you must first encrypt the `value` (if b
struct request
{
std::string type; // The mapping type, "session" or "lokinet".
std::string type; // The mapping type, "session", "lokinet", or "wallet".
std::string name; // The name to update via Loki Name Service
std::string value; // (Optional): The new value that the name maps to via Loki Name Service. If not specified or given the empty string "", then the mapping's value remains unchanged. If using a `signature` then this value (if non-empty) must be already encrypted.
std::string owner; // (Optional): The new owner of the mapping. If not specified or given the empty string "", then the mapping's owner remains unchanged.
@ -2323,9 +2323,9 @@ This command is only required if the open wallet is one of the owners of a LNS r
struct request
{
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 encrypted_value; // (Optional): The new encrypted value that the name maps to via Loki Name Service. If not specified or given the empty string "", then the mapping's value remains unchanged.
std::string type; // The mapping type, currently we support "session", "lokinet" and "wallet" mappings.
std::string name; // The desired name to update via Oxen Name Service
std::string encrypted_value; // (Optional): The new encrypted value that the name maps to via Oxen Name Service. If not specified or given the empty string "", then the mapping's value remains unchanged.
std::string owner; // (Optional): The new owner of the mapping. If not specified or given the empty string "", then the mapping's owner remains unchanged.
std::string backup_owner; // (Optional): The new backup owner of the mapping. If not specified or given the empty string "", then the mapping's backup owner remains unchanged.
uint32_t account_index; // (Optional) Use this wallet's subaddress account for generating the signature
@ -2349,7 +2349,7 @@ This command is only required if the open wallet is one of the owners of a LNS r
struct request
{
std::string type; // The mapping type, "session" or "lokinet".
std::string type; // The mapping type, "session", "lokinet" or "wallet".
std::string name; // The desired name to hash
KV_MAP_SERIALIZABLE

View File

@ -1080,14 +1080,19 @@ struct lns_keys_t
static lns_keys_t make_lns_keys(cryptonote::account_base const &src)
{
lns_keys_t result = {};
result.owner = lns::make_monero_owner(src.get_keys().m_account_address, false /*is_subaddress*/);
result.session_value.len = lns::SESSION_PUBLIC_KEY_BINARY_LENGTH;
result.wallet_value.len = sizeof(src.get_keys().m_account_address);
ons_keys_t result = {};
result.owner = ons::make_monero_owner(src.get_keys().m_account_address, false /*is_subaddress*/);
result.session_value.len = ons::SESSION_PUBLIC_KEY_BINARY_LENGTH;
result.wallet_value.len = ons::WALLET_ACCOUNT_BINARY_LENGTH_NO_PAYMENT_ID;
result.lokinet_value.len = sizeof(result.owner.wallet.address.m_spend_public_key);
memcpy(&result.session_value.buffer[0] + 1, &result.owner.wallet.address.m_spend_public_key, result.lokinet_value.len);
memcpy(&result.wallet_value.buffer[0], (char *)&src.get_keys().m_account_address, result.wallet_value.len);
auto iter = result.wallet_value.buffer.begin();
uint8_t identifier = 0;
iter = std::copy_n(&identifier, 1, iter);
iter = std::copy_n(src.get_keys().m_account_address.m_spend_public_key.data, sizeof(&src.get_keys().m_account_address.m_spend_public_key.data), iter);
iter = std::copy_n(src.get_keys().m_account_address.m_view_public_key.data, sizeof(&src.get_keys().m_account_address.m_view_public_key.data), iter);
// NOTE: Just needs a 32 byte key. Reuse spend key
memcpy(&result.lokinet_value.buffer[0], (char *)&result.owner.wallet.address.m_spend_public_key, result.lokinet_value.len);
@ -1117,8 +1122,8 @@ bool oxen_name_system_expiration::generate(std::vector<test_event_entry> &events
mapping_type <= lns::mapping_type::lokinet_10years;
mapping_type = static_cast<lns::mapping_type>(static_cast<uint16_t>(mapping_type) + 1))
{
std::string const name = "mydomain.oxen";
if (lns::mapping_type_allowed(gen.hardfork(), mapping_type))
std::string const name = "mydomain.loki";
if (ons::mapping_type_allowed(gen.hardfork(), mapping_type))
{
cryptonote::transaction tx = gen.create_and_add_oxen_name_system_tx(miner, gen.hardfork(), mapping_type, name, miner_key.lokinet_value);
gen.create_and_add_next_block({tx});
@ -1419,9 +1424,9 @@ bool oxen_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
gen.create_and_add_next_block({transfer});
gen.add_transfer_unlock_blocks();
lns_keys_t miner_key = make_lns_keys(miner);
lns_keys_t bob_key = make_lns_keys(bob);
std::string session_name = "myfriendlydisplayname.oxen";
ons_keys_t miner_key = make_ons_keys(miner);
ons_keys_t bob_key = make_ons_keys(bob);
std::string session_name = "myfriendlydisplayname.loki";
std::string lokinet_name = session_name;
auto custom_type = static_cast<lns::mapping_type>(3928);
crypto::hash session_tx_hash = {}, lokinet_tx_hash = {};
@ -1497,8 +1502,8 @@ bool oxen_name_system_handles_duplicate_in_tx_pool::generate(std::vector<test_ev
gen.add_transfer_unlock_blocks();
}
lns_keys_t bob_key = make_lns_keys(bob);
std::string session_name = "myfriendlydisplayname.oxen";
ons_keys_t bob_key = make_ons_keys(bob);
std::string session_name = "myfriendlydisplayname.loki";
auto custom_type = static_cast<lns::mapping_type>(3928);
{
@ -1664,9 +1669,9 @@ bool oxen_name_system_large_reorg::generate(std::vector<test_event_entry> &event
gen.add_transfer_unlock_blocks();
}
// NOTE: Generate the first round of LNS transactions belonging to miner
uint64_t first_lns_height = 0;
std::string const lokinet_name1 = "website.oxen";
// NOTE: Generate the first round of ONS transactions belonging to miner
uint64_t first_ons_height = 0;
std::string const lokinet_name1 = "website.loki";
std::string const wallet_name1 = "MyWallet";
std::string const session_name1 = "I-Like-Loki";
crypto::hash session_tx_hash1 = {}, wallet_tx_hash1 = {}, lokinet_tx_hash1 = {};
@ -1870,9 +1875,9 @@ bool oxen_name_system_name_renewal::generate(std::vector<test_event_entry> &even
gen.add_mined_money_unlock_blocks();
}
lns_keys_t miner_key = make_lns_keys(miner);
std::string const name = "mydomain.oxen";
cryptonote::transaction tx = gen.create_and_add_oxen_name_system_tx(miner, gen.hardfork(), lns::mapping_type::lokinet, name, miner_key.lokinet_value);
ons_keys_t miner_key = make_ons_keys(miner);
std::string const name = "mydomain.loki";
cryptonote::transaction tx = gen.create_and_add_oxen_name_system_tx(miner, gen.hardfork(), ons::mapping_type::lokinet, name, miner_key.lokinet_value);
gen.create_and_add_next_block({tx});
crypto::hash prev_txid = get_transaction_hash(tx);
@ -1988,8 +1993,8 @@ bool oxen_name_system_name_value_max_lengths::generate(std::vector<test_event_en
// Lokinet
if (lns::mapping_type_allowed(gen.hardfork(), lns::mapping_type::lokinet))
{
std::string name(lns::LOKINET_DOMAIN_NAME_MAX, 'a');
name.replace(name.size() - 6, 5, ".oxen");
std::string name(ons::LOKINET_DOMAIN_NAME_MAX, 'a');
name.replace(name.size() - 6, 5, ".loki");
data.type = lns::mapping_type::lokinet;
data.name_hash = lns::name_to_hash(name);
@ -2021,8 +2026,8 @@ bool oxen_name_system_update_mapping_after_expiry_fails::generate(std::vector<te
lns_keys_t miner_key = make_lns_keys(miner);
if (lns::mapping_type_allowed(gen.hardfork(), lns::mapping_type::lokinet))
{
std::string const name = "mydomain.oxen";
cryptonote::transaction tx = gen.create_and_add_oxen_name_system_tx(miner, gen.hardfork(), lns::mapping_type::lokinet, name, miner_key.lokinet_value);
std::string const name = "mydomain.loki";
cryptonote::transaction tx = gen.create_and_add_oxen_name_system_tx(miner, gen.hardfork(), ons::mapping_type::lokinet, name, miner_key.lokinet_value);
crypto::hash tx_hash = cryptonote::get_transaction_hash(tx);
gen.create_and_add_next_block({tx});
@ -2531,8 +2536,8 @@ bool oxen_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
}
else if (type == lns::mapping_type::lokinet)
{
value = lns_keys.lokinet_value;
name = "myfriendlylokinetname.oxen";
value = ons_keys.lokinet_value;
name = "myfriendlylokinetname.loki";
}
else
assert("Unhandled type enum" == nullptr);