Code review

- constexpr functions in common/loki.h for inlining
- move hex functions out from common/loki.h to common/hex.h
- use and apply prev_txid on LNS TX's to all LNS types (for updating in the future)
- add lns burn type, for custom burn amounts
- accept and validate lokinet addresses via base32z
- return lokinet addresses in RPC LNS calls via base32z
- updated Messenger references to Session
- update documentation to note that only Session LNS entries are allowed currently
- remove raw c-string interface from LNS db
- update multi-SQL queries into single SQL queries
- remove tx estimation backlog in anticipation for 2 priorities only, blink + unimportant
This commit is contained in:
Doyle 2020-02-11 17:36:34 +11:00
parent dafc95ac91
commit e3a6f20f85
27 changed files with 747 additions and 452 deletions

View File

@ -30,6 +30,7 @@
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
set(common_sources
base32z.cpp
base58.cpp
command_line.cpp
dns_utils.cpp
@ -65,6 +66,7 @@ set(common_headers)
set(common_private_headers
apply_permutation.h
base32z.h
base58.h
boost_serialization_helper.h
command_line.h

53
src/common/base32z.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "base32z.h"
#include "crypto/crypto.h"
#include <unordered_map>
namespace base32z
{
static const std::unordered_map<char, uint8_t> zbase32_reverse_alpha = {
{'y', 0}, {'b', 1}, {'n', 2}, {'d', 3}, {'r', 4}, {'f', 5}, {'g', 6}, {'8', 7},
{'e', 8}, {'j', 9}, {'k', 10}, {'m', 11}, {'c', 12}, {'p', 13}, {'q', 14}, {'x', 15},
{'o', 16}, {'t', 17}, {'1', 18}, {'u', 19}, {'w', 20}, {'i', 21}, {'s', 22}, {'z', 23},
{'a', 24}, {'3', 25}, {'4', 26}, {'5', 27}, {'h', 28}, {'7', 29}, {'6', 30}, {'9', 31}};
static size_t decode_size(size_t sz)
{
auto d = div(sz, 5);
if (d.rem) d.quot++;
return 8 * d.quot;
}
bool decode(std::string const &src, crypto::ed25519_public_key &dest)
{
int tmp = 0, bits = 0;
size_t idx = 0;
const size_t len = decode_size(sizeof(dest));
const size_t out_len = sizeof(dest);
for (size_t i = 0; i < len; i++)
{
char ch = src[i];
if (ch)
{
auto itr = zbase32_reverse_alpha.find(ch);
if (itr == zbase32_reverse_alpha.end()) return false;
ch = itr->second;
}
else
{
return idx == out_len;
}
tmp |= ch;
bits += 5;
if (bits >= 8)
{
if (idx >= out_len) return false;
dest.data[idx] = tmp >> (bits - 8);
bits -= 8;
idx++;
}
tmp <<= 5;
}
return idx == out_len;
}
}

55
src/common/base32z.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include <string>
namespace crypto
{
struct ed25519_public_key;
};
namespace base32z
{
bool decode(std::string const &src, crypto::ed25519_public_key &dest);
/// adapted from i2pd
template <typename stack_t>
const char *encode(std::string const &src, stack_t &stack)
{
// from https://en.wikipedia.org/wiki/Base32#z-base-32
static const char zbase32_alpha[] = {'y', 'b', 'n', 'd', 'r', 'f', 'g', '8', 'e', 'j', 'k', 'm', 'c', 'p', 'q', 'x',
'o', 't', '1', 'u', 'w', 'i', 's', 'z', 'a', '3', '4', '5', 'h', '7', '6', '9'};
size_t ret = 0, pos = 1;
int bits = 8;
uint32_t tmp = src[0];
size_t len = sizeof(src);
while (ret < sizeof(stack) && (bits > 0 || pos < len))
{
if (bits < 5)
{
if (pos < len)
{
tmp <<= 8;
tmp |= src[pos] & 0xFF;
pos++;
bits += 8;
}
else // last byte
{
tmp <<= (5 - bits);
bits = 5;
}
}
bits -= 5;
int ind = (tmp >> bits) & 0x1F;
if (ret < sizeof(stack))
{
stack[ret] = zbase32_alpha[ind];
ret++;
}
else
return nullptr;
}
return &stack[0];
}
};

36
src/common/hex.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
namespace hex
{
constexpr bool char_is_hex(char c)
{
bool result = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
return result;
}
constexpr char from_hex_digit(char x) {
return
(x >= '0' && x <= '9') ? x - '0' :
(x >= 'a' && x <= 'f') ? x - ('a' - 10):
(x >= 'A' && x <= 'F') ? x - ('A' - 10):
0;
}
constexpr char from_hex_pair(char a, char b) { return (from_hex_digit(a) << 4) | from_hex_digit(b); }
// Creates a string from a character sequence of hex digits. Undefined behaviour if any characters
// are not in [0-9a-fA-F] or if the input sequence length is not even.
template <typename It>
std::string from_hex(It begin, It end) {
using std::distance;
using std::next;
assert(distance(begin, end) % 2 == 0);
std::string raw;
raw.reserve(distance(begin, end) / 2);
while (begin != end) {
char a = *begin++;
char b = *begin++;
raw += from_hex_pair(a, b);
}
return raw;
}
}

View File

@ -498,17 +498,3 @@ loki::round (double x)
return z;
}
uint64_t loki::clamp_u64(uint64_t val, uint64_t min, uint64_t max)
{
assert(min <= max);
if (val < min) val = min;
else if (val > max) val = max;
return val;
}
bool loki::char_is_hex(char c)
{
bool result = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
return result;
}

View File

@ -36,39 +36,20 @@
#include <cstdint>
#include <string>
#include <iterator>
#include <cassert>
#define LOKI_RPC_DOC_INTROSPECT
namespace loki
{
double round (double);
double exp2 (double);
uint64_t clamp_u64 (uint64_t val, uint64_t min, uint64_t max);
bool char_is_hex (char c);
constexpr char from_hex_digit(char x) {
return
(x >= '0' && x <= '9') ? x - '0' :
(x >= 'a' && x <= 'f') ? x - ('a' - 10):
(x >= 'A' && x <= 'F') ? x - ('A' - 10):
0;
}
constexpr char from_hex_pair(char a, char b) { return (from_hex_digit(a) << 4) | from_hex_digit(b); }
// Creates a string from a character sequence of hex digits. Undefined behaviour if any characters
// are not in [0-9a-fA-F] or if the input sequence length is not even.
template <typename It>
std::string from_hex(It begin, It end) {
using std::distance;
using std::next;
assert(distance(begin, end) % 2 == 0);
std::string raw;
raw.reserve(distance(begin, end) / 2);
while (begin != end) {
char a = *begin++;
char b = *begin++;
raw += from_hex_pair(a, b);
}
return raw;
constexpr uint64_t clamp_u64(uint64_t val, uint64_t min, uint64_t max)
{
assert(min <= max);
if (val < min) val = min;
else if (val > max) val = max;
return val;
}
template <typename lambda_t>

View File

@ -62,18 +62,6 @@
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
namespace lns
{
enum struct mapping_type : uint16_t
{
messenger = 0,
start_reserved = 1,
blockchain = 2,
lokinet = 3,
end_reserved = 64,
};
}
namespace service_nodes {
enum class new_state : uint16_t
{
@ -401,7 +389,7 @@ namespace cryptonote
uint16_t type;
std::string name;
std::string value; // binary format of the name->value mapping
crypto::hash prev_txid = crypto::null_hash; // previous txid that purchased the mapping, only applicable if lokinet
crypto::hash prev_txid = crypto::null_hash; // previous txid that purchased the mapping
tx_extra_loki_name_system() = default;
tx_extra_loki_name_system(crypto::ed25519_public_key const &owner, uint16_t type, std::string const &name, std::string const &value, crypto::hash const &prev_txid)
@ -419,8 +407,7 @@ namespace cryptonote
FIELD(type);
FIELD(name);
FIELD(value);
if (type == static_cast<uint16_t>(lns::mapping_type::lokinet))
FIELD(prev_txid);
FIELD(prev_txid);
END_SERIALIZE()
};

View File

@ -2,6 +2,8 @@
#include "checkpoints/checkpoints.h"
#include "common/loki.h"
#include "common/hex.h"
#include "common/base32z.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
@ -32,6 +34,7 @@ enum struct lns_sql_type
get_setting,
get_mapping,
get_mappings_by_user,
get_mapping_by_name_and_type,
get_mappings_on_height_and_newer,
get_sentinel_end,
};
@ -60,6 +63,7 @@ enum struct mapping_record_row
prev_txid,
register_height,
user_id,
_count,
};
static bool sql_copy_blob(sqlite3_stmt *statement, int row, void *dest, int dest_size)
@ -118,6 +122,7 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
}
break;
case lns_sql_type::get_mapping_by_name_and_type: /* FALLTHRU */
case lns_sql_type::get_mappings_on_height_and_newer: /* FALLTHRU */
case lns_sql_type::get_mappings_by_user: /* FALLTHRU */
case lns_sql_type::get_mapping:
@ -142,16 +147,27 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
if (!sql_copy_blob(statement, static_cast<int>(mapping_record_row::prev_txid), tmp_entry.prev_txid.data, sizeof(tmp_entry.prev_txid)))
return false;
data_loaded = true;
if (type == lns_sql_type::get_mappings_by_user || type == lns_sql_type::get_mappings_on_height_and_newer)
if (type == lns_sql_type::get_mapping_by_name_and_type)
{
int constexpr last_column = tools::enum_count<mapping_record_row> + 1;
auto *entry = reinterpret_cast<mapping_and_user_record *>(context);
if (!sql_copy_blob(statement, last_column, entry->owner.data, sizeof(entry->owner)))
return false;
entry->mapping = std::move(tmp_entry);
}
else if (type == lns_sql_type::get_mappings_by_user || type == lns_sql_type::get_mappings_on_height_and_newer)
{
auto *records = reinterpret_cast<std::vector<mapping_record> *>(context);
records->emplace_back(std::move(tmp_entry));
}
else
{
mapping_record *entry = reinterpret_cast<mapping_record *>(context);
*entry = std::move(tmp_entry);
auto *entry = reinterpret_cast<mapping_record *>(context);
*entry = std::move(tmp_entry);
}
}
break;
@ -198,10 +214,32 @@ static bool sql_compile_statement(sqlite3 *db, char const *query, int query_len,
return result;
}
uint64_t burn_requirement_in_atomic_loki(uint8_t hf_version)
burn_type mapping_type_to_burn_type(mapping_type in)
{
(void)hf_version;
return 30 * COIN;
burn_type result = burn_type::custom;
switch (in)
{
case mapping_type::lokinet: result = burn_type::lokinet_1year; break;
case mapping_type::session: result = burn_type::session; break;
case mapping_type::wallet: result = burn_type::wallet; break;
default: break;
}
return result;
}
uint64_t burn_requirement_in_atomic_loki(uint8_t /*hf_version*/, burn_type type)
{
uint64_t result = 0;
switch (type)
{
case burn_type::lokinet_1year: /* FALLTHRU */
case burn_type::session: /* FALLTHRU */
case burn_type::wallet: /* FALLTHRU */
case burn_type::custom: /* FALLTHRU */
default: result = 30 * COIN;
break;
}
return result;
}
sqlite3 *init_loki_name_system(char const *file_path)
@ -261,29 +299,28 @@ static bool char_is_alphanum(char c)
return result;
}
bool validate_lns_name(uint16_t type, char const *name, int name_len, std::string *reason)
bool validate_lns_name(uint16_t type, std::string const &name, std::string *reason)
{
std::stringstream err_stream;
LOKI_DEFER { if (reason) *reason = err_stream.str(); };
int max_name_len = lns::GENERIC_NAME_MAX;
if (type == static_cast<uint16_t>(mapping_type::messenger)) max_name_len = lns::MESSENGER_DISPLAY_NAME_MAX;
else if (type == static_cast<uint16_t>(mapping_type::blockchain)) max_name_len = lns::BLOCKCHAIN_NAME_MAX;
else if (type == static_cast<uint16_t>(mapping_type::lokinet)) max_name_len = lns::LOKINET_DOMAIN_NAME_MAX;
size_t max_name_len = lns::GENERIC_NAME_MAX;
if (type == static_cast<uint16_t>(mapping_type::session)) max_name_len = lns::SESSION_DISPLAY_NAME_MAX;
else if (type == static_cast<uint16_t>(mapping_type::wallet)) max_name_len = lns::WALLET_NAME_MAX;
else if (type == static_cast<uint16_t>(mapping_type::lokinet)) max_name_len = lns::LOKINET_DOMAIN_NAME_MAX;
// NOTE: Validate name length
if (name_len > max_name_len || name_len == 0)
if (name.empty() || name.size() > max_name_len)
{
if (reason)
{
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the name's length=" << name_len << " is 0 or exceeds the maximum length=" << max_name_len << ", given name=";
err_stream.write(name, name_len);
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the name's length=" << name.size() << " is 0 or exceeds the maximum length=" << max_name_len << ", given name=" << name;
}
return false;
}
// NOTE: Validate domain specific requirements
if (type == static_cast<uint16_t>(mapping_type::messenger))
if (type == static_cast<uint16_t>(mapping_type::session))
{
}
else if (type == static_cast<uint16_t>(mapping_type::lokinet))
@ -292,12 +329,11 @@ bool validate_lns_name(uint16_t type, char const *name, int name_len, std::strin
// ^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.loki$
{
char const SHORTEST_DOMAIN[] = "a.loki";
if (name_len < static_cast<int>(loki::char_count(SHORTEST_DOMAIN)))
if (name.size() < static_cast<int>(loki::char_count(SHORTEST_DOMAIN)))
{
if (reason)
{
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the name is shorter than the shortest possible name=" << SHORTEST_DOMAIN << ", given name=";
err_stream.write(name, name_len);
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the name is shorter than the shortest possible name=" << SHORTEST_DOMAIN << ", given name=" << name;
}
return false;
}
@ -307,20 +343,18 @@ bool validate_lns_name(uint16_t type, char const *name, int name_len, std::strin
{
if (reason)
{
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the name does not start with an alphanumeric character, name=";
err_stream.write(name, name_len);
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the name does not start with an alphanumeric character, name=" << name;
}
return false;
}
char const SUFFIX[] = ".loki";
char const *name_suffix = name + (name_len - loki::char_count(SUFFIX));
char const *name_suffix = name.data() + (name.size() - loki::char_count(SUFFIX));
if (memcmp(name_suffix, SUFFIX, loki::char_count(SUFFIX)) != 0) // Must end with .loki
{
if (reason)
{
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the name does not end with the domain .loki, name=";
err_stream.write(name, name_len);
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the name does not end with the domain .loki, name=" << name;
}
return false;
}
@ -330,13 +364,12 @@ bool validate_lns_name(uint16_t type, char const *name, int name_len, std::strin
{
if (reason)
{
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the character preceeding the <char>.loki is not alphanumeric, char=" << char_preceeding_suffix[0] << ", name=";
err_stream.write(name, name_len);
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the character preceeding the <char>.loki is not alphanumeric, char=" << char_preceeding_suffix[0] << ", name=" << name;
}
return false;
}
char const *begin = name + 1;
char const *begin = name.data() + 1;
char const *end = char_preceeding_suffix;
for (char const *it = begin; it < end; it++) // Inbetween start and preceeding suffix, alphanumeric and hyphen characters permitted
{
@ -345,8 +378,7 @@ bool validate_lns_name(uint16_t type, char const *name, int name_len, std::strin
{
if (reason)
{
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the domain name contains more than the permitted alphanumeric or hyphen characters name=";
err_stream.write(name, name_len);
err_stream << "LNS type=lokinet, specifies mapping from name -> value where the domain name contains more than the permitted alphanumeric or hyphen characters name=" << name;
}
return false;
}
@ -356,17 +388,17 @@ bool validate_lns_name(uint16_t type, char const *name, int name_len, std::strin
return true;
}
static bool check_lengths(uint16_t type, char const *value, int len, int max, bool require_exact_len, std::string *reason)
static bool check_lengths(uint16_t type, std::string const &value, size_t max, bool require_exact_len, std::string *reason)
{
bool result = true;
if (require_exact_len)
{
if (len != max)
if (value.size() != max)
result = false;
}
else
{
if (len > max || len == 0)
if (value.size() > max || value.size() == 0)
{
result = false;
}
@ -377,11 +409,10 @@ static bool check_lengths(uint16_t type, char const *value, int len, int max, bo
if (reason)
{
std::stringstream err_stream;
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the value's length=" << len;
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the value's length=" << value.size();
if (require_exact_len) err_stream << ", does not equal the required length=";
else err_stream <<" is 0 or exceeds the maximum length=";
err_stream << max << ", given value=";
err_stream.write(value, len);
err_stream << max << ", given value=" << value;
*reason = err_stream.str();
}
}
@ -389,32 +420,30 @@ static bool check_lengths(uint16_t type, char const *value, int len, int max, bo
return result;
}
bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, char const *value, int value_len, lns_value *blob, std::string *reason)
bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, std::string const &value, lns_value *blob, std::string *reason)
{
if (blob) *blob = {};
std::stringstream err_stream;
cryptonote::address_parse_info addr_info = {};
static_assert(GENERIC_VALUE_MAX >= MESSENGER_PUBLIC_KEY_BINARY_LENGTH, "lns_value assumes the largest blob size required, all other values should be able to fit into this buffer");
static_assert(GENERIC_VALUE_MAX >= SESSION_PUBLIC_KEY_BINARY_LENGTH, "lns_value assumes the largest blob size required, all other values should be able to fit into this buffer");
static_assert(GENERIC_VALUE_MAX >= LOKINET_ADDRESS_BINARY_LENGTH, "lns_value assumes the largest blob size required, all other values should be able to fit into this buffer");
static_assert(GENERIC_VALUE_MAX >= sizeof(addr_info.address), "lns_value assumes the largest blob size required, all other values should be able to fit into this buffer");
if (type == static_cast<uint16_t>(mapping_type::blockchain))
if (type == static_cast<uint16_t>(mapping_type::wallet))
{
if (value_len == 0 || !get_account_address_from_str(addr_info, nettype, std::string(value, value_len)))
if (value.empty() || !get_account_address_from_str(addr_info, nettype, value))
{
if (reason)
{
if (value_len == 0)
if (value.empty())
{
err_stream << "The value=";
err_stream.write(value, value_len);
err_stream << "The value=" << value;
err_stream << ", mapping into the wallet address, specifies a wallet address of 0 length";
}
else
{
err_stream << "Could not convert the wallet address string, check it is correct, value=";
err_stream.write(value, value_len);
err_stream << "Could not convert the wallet address string, check it is correct, value=" << value;
}
*reason = err_stream.str();
}
@ -426,14 +455,14 @@ bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, char co
int max_value_len = lns::GENERIC_VALUE_MAX;
bool value_require_exact_len = true;
if (type == static_cast<uint16_t>(mapping_type::lokinet)) max_value_len = (LOKINET_ADDRESS_BINARY_LENGTH * 2);
else if (type == static_cast<uint16_t>(mapping_type::messenger)) max_value_len = (MESSENGER_PUBLIC_KEY_BINARY_LENGTH * 2);
else if (type == static_cast<uint16_t>(mapping_type::session)) max_value_len = (SESSION_PUBLIC_KEY_BINARY_LENGTH * 2);
else value_require_exact_len = false;
if (!check_lengths(type, value, value_len, max_value_len, value_require_exact_len, reason))
if (!check_lengths(type, value, max_value_len, value_require_exact_len, reason))
return false;
}
if (type == static_cast<uint16_t>(mapping_type::blockchain))
if (type == static_cast<uint16_t>(mapping_type::wallet))
{
if (blob)
{
@ -441,51 +470,75 @@ bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, char co
memcpy(blob->buffer.data(), &addr_info.address, blob->len);
}
}
else
else if (type == static_cast<uint16_t>(mapping_type::lokinet))
{
// NOTE: Check value is hex
if ((value_len % 2) != 0)
if (value.size() != 52)
{
if (reason)
{
err_stream << "The value=";
err_stream.write(value, value_len);
err_stream << ", should be a hex string that has an even length to be convertible back into binary, length=" << value_len;
err_stream << "The lokinet value=" << value << ", should be a 52 char base32z string, length=" << value.size();
*reason = err_stream.str();
}
return false;
}
for (int val_index = 0; val_index < value_len; val_index += 2)
crypto::ed25519_public_key pkey;
if (!base32z::decode(value, pkey))
{
if (reason)
{
err_stream << "The value=" << value << ", was not a decodable base32z value.";
*reason = err_stream.str();
}
return false;
}
if (blob)
{
blob->len = sizeof(pkey);
memcpy(blob->buffer.data(), pkey.data, blob->len);
}
}
else
{
// NOTE: Check value is hex
if ((value.size() % 2) != 0)
{
if (reason)
{
err_stream << "The value=" << value << ", should be a hex string that has an even length to be convertible back into binary, length=" << value.size();
*reason = err_stream.str();
}
return false;
}
for (size_t val_index = 0; val_index < value.size(); val_index += 2)
{
char a = value[val_index];
char b = value[val_index + 1];
if (loki::char_is_hex(a) && loki::char_is_hex(b))
if (hex::char_is_hex(a) && hex::char_is_hex(b))
{
if (blob) // NOTE: Given blob, write the binary output
blob->buffer.data()[blob->len++] = loki::from_hex_pair(a, b);
blob->buffer.data()[blob->len++] = hex::from_hex_pair(a, b);
}
else
{
if (reason)
{
err_stream << "LNS type=" << type <<", specifies name -> value mapping where the value is not a hex string given value=";
err_stream.write(value, value_len);
err_stream << "LNS type=" << type <<", specifies name -> value mapping where the value is not a hex string given value=" << value;
*reason = err_stream.str();
}
return false;
}
}
if (type == static_cast<uint16_t>(mapping_type::messenger))
if (type == static_cast<uint16_t>(mapping_type::session))
{
if (!(value[0] == '0' && value[1] == '5')) // NOTE: Messenger public keys are 33 bytes, with the first byte being 0x05 and the remaining 32 being the public key.
if (!(value[0] == '0' && value[1] == '5')) // NOTE: Session public keys are 33 bytes, with the first byte being 0x05 and the remaining 32 being the public key.
{
if (reason)
{
err_stream << "LNS type=messenger, specifies mapping from name -> ed25519 key where the key is not prefixed with 53 (0x05), prefix=";
err_stream << std::to_string(value[0]) << " (" << value[0] << "), given ed25519=";
err_stream.write(value, value_len);
err_stream << "LNS type=session, specifies mapping from name -> ed25519 key where the key is not prefixed with 53 (0x05), prefix=" << std::to_string(value[0]) << " (" << value[0] << "), given ed25519=" << value;
*reason = err_stream.str();
}
return false;
@ -495,30 +548,29 @@ bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, char co
return true;
}
bool validate_lns_value_binary(uint16_t type, char const *value, int value_len, std::string *reason)
bool validate_lns_value_binary(uint16_t type, std::string const &value, std::string *reason)
{
int max_value_len = lns::GENERIC_VALUE_MAX;
bool value_require_exact_len = true;
if (type == static_cast<uint16_t>(mapping_type::lokinet)) max_value_len = LOKINET_ADDRESS_BINARY_LENGTH;
else if (type == static_cast<uint16_t>(mapping_type::messenger)) max_value_len = MESSENGER_PUBLIC_KEY_BINARY_LENGTH;
else if (type == static_cast<uint16_t>(mapping_type::blockchain)) max_value_len = sizeof(cryptonote::account_public_address);
if (type == static_cast<uint16_t>(mapping_type::lokinet)) max_value_len = LOKINET_ADDRESS_BINARY_LENGTH;
else if (type == static_cast<uint16_t>(mapping_type::session)) max_value_len = SESSION_PUBLIC_KEY_BINARY_LENGTH;
else if (type == static_cast<uint16_t>(mapping_type::wallet)) max_value_len = sizeof(cryptonote::account_public_address);
else value_require_exact_len = false;
if (!check_lengths(type, value, value_len, max_value_len, value_require_exact_len, reason))
if (!check_lengths(type, value, max_value_len, value_require_exact_len, reason))
return false;
if (type == static_cast<uint16_t>(lns::mapping_type::blockchain))
if (type == static_cast<uint16_t>(lns::mapping_type::wallet))
{
// TODO(doyle): Better address validation? Is it a valid address, is it a valid nettype address?
cryptonote::account_public_address address;
memcpy(&address, value, sizeof(address));
memcpy(&address, value.data(), sizeof(address));
if (!(crypto::check_key(address.m_spend_public_key) && crypto::check_key(address.m_view_public_key)))
{
if (reason)
{
std::stringstream err_stream;
err_stream << "LNS type=" << type << ", specifies mapping from name -> wallet address where the wallet address's blob does not generate valid public spend/view keys";
err_stream.write(value, value_len);
err_stream << "LNS type=" << type << ", specifies mapping from name -> wallet address where the wallet address's blob, does not generate valid public spend/view keys";
*reason = err_stream.str();
}
return false;
@ -537,7 +589,7 @@ static bool validate_against_previous_mapping(lns::name_system_db const &lns_db,
{
std::stringstream err_stream;
crypto::hash expected_prev_txid = crypto::null_hash;
if (lns::mapping_record mapping = lns_db.get_mapping(data.type, data.name.data(), data.name.size()))
if (lns::mapping_record mapping = lns_db.get_mapping(data.type, data.name))
{
if (data.type != static_cast<uint16_t>(lns::mapping_type::lokinet))
{
@ -639,7 +691,7 @@ bool name_system_db::validate_lns_tx(uint8_t hf_version, uint64_t blockchain_hei
return false;
}
if (entry->type >= static_cast<uint16_t>(lns::mapping_type::start_reserved) && entry->type <= static_cast<uint16_t>(mapping_type::end_reserved))
if (entry->type >= static_cast<uint16_t>(lns::mapping_type::start_unusable_range) && entry->type <= static_cast<uint16_t>(mapping_type::end_unusable_range))
{
if (reason)
{
@ -648,18 +700,18 @@ bool name_system_db::validate_lns_tx(uint8_t hf_version, uint64_t blockchain_hei
}
return false;
}
uint64_t burn = cryptonote::get_burned_amount_from_tx_extra(tx.extra);
if (!validate_lns_name(entry->type, entry->name.data(), static_cast<int>(entry->name.size()), reason))
if (!validate_lns_name(entry->type, entry->name, reason))
return false;
if (!validate_lns_value_binary(entry->type, entry->value.data(), static_cast<int>(entry->value.size()), reason))
if (!validate_lns_value_binary(entry->type, entry->value, reason))
return false;
if (!validate_against_previous_mapping(*this, blockchain_height, tx, *entry, reason))
return false;
uint64_t const burn_required = burn_requirement_in_atomic_loki(hf_version);
auto lns_type = static_cast<mapping_type>(entry->type);
uint64_t const burn_required = burn_requirement_in_atomic_loki(hf_version, mapping_type_to_burn_type(lns_type));
if (burn != burn_required)
{
if (reason)
@ -684,9 +736,7 @@ bool validate_mapping_type(std::string const &type, uint16_t *mapping_type, std:
}
uint16_t mapping_type_ = 0;
if (type_lowered == "blockchain") mapping_type_ = static_cast<uint16_t>(lns::mapping_type::blockchain);
else if (type_lowered == "lokinet") mapping_type_ = static_cast<uint16_t>(lns::mapping_type::lokinet);
else if (type_lowered == "messenger") mapping_type_ = static_cast<uint16_t>(lns::mapping_type::messenger);
if (type_lowered == "session") mapping_type_ = static_cast<uint16_t>(lns::mapping_type::session);
else
{
try
@ -694,14 +744,14 @@ bool validate_mapping_type(std::string const &type, uint16_t *mapping_type, std:
size_t value = std::stoul(type_lowered);
if (value > std::numeric_limits<uint16_t>::max())
{
if (reason) *reason = "LNS custom type specifies value too large, must be from 0-65536: " + std::to_string(value);
if (reason) *reason = "LNS type specifies value too large, must be from 0-65535: " + std::to_string(value);
return false;
}
mapping_type_ = static_cast<uint16_t>(value);
}
catch (std::exception const &)
{
if (reason) *reason = "Failed to convert custom lns mapping argument (was not proper integer, or not one of the recognised arguments blockchain, lokinet, messenger), string was: " + type;
if (reason) *reason = "Failed to convert lns mapping (was not proper integer, or not one of the recognised: \"session\"), string was=" + type;
return false;
}
}
@ -763,11 +813,14 @@ bool name_system_db::init(cryptonote::network_type nettype, sqlite3 *db, uint64_
char constexpr GET_SETTINGS_SQL[] = R"(SELECT * FROM "settings" WHERE "id" = 0)";
char constexpr GET_USER_BY_KEY_SQL[] = R"(SELECT * FROM "user" WHERE "public_key" = ?)";
char constexpr GET_USER_BY_ID_SQL[] = R"(SELECT * FROM "user" WHERE "id" = ?)";
char constexpr GET_MAPPINGS_BY_USER_SQL[] = R"(SELECT * FROM "mappings" WHERE "user_id" = ?)";
char constexpr GET_MAPPINGS_ON_HEIGHT_AND_NEWER_SQL[] = R"(SELECT * FROM mappings WHERE "register_height" >= ?)";
char constexpr GET_MAPPINGS_ON_HEIGHT_AND_NEWER_SQL[] = R"(SELECT * FROM "mappings" WHERE "register_height" >= ?)";
char constexpr SAVE_SETTINGS_SQL[] = R"(INSERT OR REPLACE INTO "settings" ("rowid", "top_height", "top_hash", "version") VALUES (1,?,?,?))";
char constexpr SAVE_MAPPING_SQL[] = R"(INSERT OR REPLACE INTO "mappings" ("type", "name", "value", "txid", "prev_txid", "register_height", "user_id") VALUES (?,?,?,?,?,?,?))";
char constexpr SAVE_USER_SQL[] = R"(INSERT INTO "user" ("public_key") VALUES (?);)";
char constexpr GET_MAPPINGS_BY_USER_SQL[] = R"(SELECT * FROM "mappings" JOIN "user" ON "mappings"."user_id" = "user"."id" WHERE "public_key" = ?)";
char constexpr GET_MAPPING_BY_NAME_AND_TYPE_SQL[] = R"(SELECT * FROM "mappings" JOIN "user" ON "mappings"."user_id" = "user"."id" WHERE "type" = ? AND "name" = ?)";
sqlite3_stmt *test;
if (!build_default_tables(db))
return false;
@ -782,6 +835,7 @@ bool name_system_db::init(cryptonote::network_type nettype, sqlite3 *db, uint64_
!sql_compile_statement(db, PRUNE_MAPPINGS_SQL, loki::array_count(PRUNE_MAPPINGS_SQL), &prune_mappings_sql) ||
!sql_compile_statement(db, PRUNE_USERS_SQL, loki::array_count(PRUNE_USERS_SQL), &prune_users_sql) ||
!sql_compile_statement(db, GET_MAPPINGS_BY_USER_SQL, loki::array_count(GET_MAPPINGS_BY_USER_SQL), &get_mappings_by_user_sql) ||
!sql_compile_statement(db, GET_MAPPING_BY_NAME_AND_TYPE_SQL, loki::array_count(GET_MAPPING_BY_NAME_AND_TYPE_SQL), &get_mapping_by_name_and_type_sql) ||
!sql_compile_statement(db, GET_MAPPINGS_ON_HEIGHT_AND_NEWER_SQL, loki::array_count(GET_MAPPINGS_ON_HEIGHT_AND_NEWER_SQL), &get_mappings_on_height_and_newer_sql)
)
{
@ -1083,27 +1137,22 @@ user_record name_system_db::get_user_by_id(int64_t user_id) const
return result;
}
mapping_record name_system_db::get_mapping(uint16_t type, char const *name, size_t name_len) const
mapping_record name_system_db::get_mapping(uint16_t type, std::string const &name) const
{
sqlite3_stmt *statement = get_mapping_sql;
sqlite3_clear_bindings(statement);
sqlite3_bind_int(statement, 1 /*sql param index*/, type);
sqlite3_bind_text(statement, 2 /*sql param index*/, name, name_len, nullptr /*destructor*/);
sqlite3_bind_text(statement, 2 /*sql param index*/, name.data(), name.size(), nullptr /*destructor*/);
mapping_record result = {};
result.loaded = sql_run_statement(nettype, lns_sql_type::get_mapping, statement, &result);
return result;
}
mapping_record name_system_db::get_mapping(uint16_t type, std::string const &name) const
{
mapping_record result = get_mapping(type, name.data(), name.size());
return result;
}
std::vector<mapping_record> name_system_db::get_mappings_by_user(crypto::ed25519_public_key const &key) const
{
std::vector<mapping_record> result = {};
#if 0
if (lns::user_record user = get_user_by_key(key))
{
sqlite3_stmt *statement = get_mappings_by_user_sql;
@ -1111,6 +1160,23 @@ std::vector<mapping_record> name_system_db::get_mappings_by_user(crypto::ed25519
sqlite3_bind_int(statement, 1 /*sql param index*/, user.id);
sql_run_statement(nettype, lns_sql_type::get_mappings_by_user, statement, &result);
}
#else
sqlite3_stmt *statement = get_mappings_by_user_sql;
sqlite3_clear_bindings(statement);
sqlite3_bind_blob(statement, 1 /*sql param index*/, key.data, sizeof(key), nullptr /*destructor*/);
sql_run_statement(nettype, lns_sql_type::get_mappings_by_user, statement, &result);
#endif
return result;
}
mapping_and_user_record name_system_db::get_mapping_by_name_and_type(mapping_type type, std::string const &name) const
{
mapping_and_user_record result = {};
sqlite3_stmt *statement = get_mapping_by_name_and_type_sql;
sqlite3_clear_bindings(statement);
sqlite3_bind_int(statement, 1 /*sql param index*/, static_cast<uint16_t>(type));
sqlite3_bind_text(statement, 2 /*sql param index*/, name.data(), name.size(), nullptr /*destructor*/);
sql_run_statement(nettype, lns_sql_type::get_mapping_by_name_and_type, statement, &result);
return result;
}

View File

@ -3,7 +3,6 @@
#include "crypto/crypto.h"
#include "cryptonote_config.h"
#include "cryptonote_basic/tx_extra.h"
#include <string>
@ -15,19 +14,20 @@ struct checkpoint_t;
struct block;
struct transaction;
struct account_address;
struct tx_extra_loki_name_system;
class Blockchain;
}; // namespace cryptonote
namespace lns
{
constexpr uint64_t BLOCKCHAIN_NAME_MAX = 96;
constexpr uint64_t LOKINET_DOMAIN_NAME_MAX = 253;
constexpr uint64_t LOKINET_ADDRESS_BINARY_LENGTH = sizeof(crypto::ed25519_public_key);
constexpr uint64_t MESSENGER_DISPLAY_NAME_MAX = 64;
constexpr uint64_t MESSENGER_PUBLIC_KEY_BINARY_LENGTH = 1 + sizeof(crypto::ed25519_public_key); // Messenger keys at prefixed with 0x05 + ed25519 key
constexpr uint64_t GENERIC_NAME_MAX = 255;
constexpr uint64_t GENERIC_VALUE_MAX = 255;
constexpr size_t WALLET_NAME_MAX = 96;
constexpr size_t LOKINET_DOMAIN_NAME_MAX = 253;
constexpr size_t LOKINET_ADDRESS_BINARY_LENGTH = sizeof(crypto::ed25519_public_key);
constexpr size_t SESSION_DISPLAY_NAME_MAX = 64;
constexpr size_t SESSION_PUBLIC_KEY_BINARY_LENGTH = 1 + sizeof(crypto::ed25519_public_key); // Session keys at prefixed with 0x05 + ed25519 key
constexpr size_t GENERIC_NAME_MAX = 255;
constexpr size_t GENERIC_VALUE_MAX = 255;
struct lns_value
{
@ -35,14 +35,33 @@ struct lns_value
size_t len;
};
uint64_t burn_requirement_in_atomic_loki(uint8_t hf_version);
enum struct mapping_type : uint16_t
{
session = 0,
wallet = 1,
lokinet = 2,
start_unusable_range = 3,
end_unusable_range = 64,
};
enum struct burn_type
{
none,
lokinet_1year,
session,
wallet,
custom,
};
burn_type mapping_type_to_burn_type(mapping_type in);
uint64_t burn_requirement_in_atomic_loki(uint8_t hf_version, burn_type type);
sqlite3 *init_loki_name_system(char const *file_path);
uint64_t lokinet_expiry_blocks(cryptonote::network_type nettype, uint64_t *renew_window = nullptr);
bool validate_lns_name(uint16_t type, char const *name, int name_len, std::string *reason = nullptr);
bool validate_lns_name(uint16_t type, std::string const &name, std::string *reason = nullptr);
// blob: if set, validate_lns_value will convert the value into the binary format suitable for storing into the LNS DB.
bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, char const *value, int value_len, lns_value *blob = nullptr, std::string *reason = nullptr);
bool validate_lns_value_binary(uint16_t type, char const *value, int value_len, std::string *reason = nullptr);
bool validate_lns_value(cryptonote::network_type nettype, uint16_t type, std::string const &value, lns_value *blob = nullptr, std::string *reason = nullptr);
bool validate_lns_value_binary(uint16_t type, std::string const &value, std::string *reason = nullptr);
bool validate_mapping_type(std::string const &type, uint16_t *mapping_type, std::string *reason);
@ -85,6 +104,13 @@ struct mapping_record
crypto::hash prev_txid;
};
struct mapping_and_user_record
{
operator bool() const { return mapping.loaded; }
mapping_record mapping;
crypto::ed25519_public_key owner;
};
struct name_system_db
{
bool init (cryptonote::network_type nettype, sqlite3 *db, uint64_t top_height, crypto::hash const &top_hash);
@ -101,11 +127,11 @@ struct name_system_db
user_record get_user_by_key (crypto::ed25519_public_key const &key) const;
user_record get_user_by_id (int64_t user_id) const;
mapping_record get_mapping (uint16_t type, char const *name, size_t name_len) const;
mapping_record get_mapping (uint16_t type, std::string const &name) const;
// return: Array of records in sorted order by their register height, ties dealt by name lexicographiclly
std::vector<mapping_record> get_mappings_by_user(crypto::ed25519_public_key const &key) const;
mapping_and_user_record get_mapping_by_name_and_type(mapping_type type, std::string const &name) const;
settings_record get_settings () const;
bool validate_lns_tx(uint8_t hf_version, uint64_t blockchain_height, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system *entry = nullptr, std::string *reason = nullptr) const;
@ -127,6 +153,7 @@ private:
sqlite3_stmt *prune_users_sql = nullptr;
sqlite3_stmt *get_mappings_by_user_sql = nullptr;
sqlite3_stmt *get_mappings_on_height_and_newer_sql = nullptr;
sqlite3_stmt *get_mapping_by_name_and_type_sql = nullptr;
};

View File

@ -1,6 +1,6 @@
#include "sn_network.h"
#include "bt_serialize.h"
#include "common/loki.h"
#include "common/hex.h"
#include <ostream>
#ifdef __cpp_lib_string_view
#include <string_view>
@ -934,7 +934,7 @@ void SNNetwork::proxy_to_worker(size_t conn_index, std::list<zmq::message_t> &&p
const char *pubkey_hex = parts.back().gets("User-Id");
auto len = std::strlen(pubkey_hex);
assert(len == 66 && (pubkey_hex[0] == 'S' || pubkey_hex[0] == 'C') && pubkey_hex[1] == ':');
pubkey = loki::from_hex(pubkey_hex + 2, pubkey_hex + 66);
pubkey = hex::from_hex(pubkey_hex + 2, pubkey_hex + 66);
remote_is_sn = pubkey_hex[0] == 'S';
} catch (...) {
SN_LOG(error, "Internal error: socket User-Id not set or invalid; dropping message");

View File

@ -45,6 +45,7 @@ using namespace epee;
#include "common/util.h"
#include "common/perf_timer.h"
#include "common/random.h"
#include "common/base32z.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
@ -3354,26 +3355,28 @@ namespace cryptonote
for (uint16_t type : request.types)
{
if (lns::mapping_record mapping = db.get_mapping(type, request.name))
if (lns::mapping_and_user_record record = db.get_mapping_by_name_and_type(static_cast<lns::mapping_type>(type), request.name))
{
if (lns::user_record user = db.get_user_by_id(mapping.user_id))
res.entries.emplace_back();
COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::response_entry &entry = res.entries.back();
entry.entry_index = request_index;
entry.type = type;
entry.owner = epee::string_tools::pod_to_hex(record.owner);
if (static_cast<lns::mapping_type>(type) == lns::mapping_type::lokinet)
{
res.entries.emplace_back();
COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::response_entry &entry = res.entries.back();
entry.entry_index = request_index;
entry.type = type;
entry.owner = epee::string_tools::pod_to_hex(user.key);
entry.pubkey = mapping.value;
entry.register_height = mapping.register_height;
entry.txid = epee::string_tools::pod_to_hex(mapping.txid);
entry.prev_txid = epee::string_tools::pod_to_hex(mapping.prev_txid);
char buf[64] = {};
base32z::encode(record.mapping.value, buf);
entry.value = std::string(buf) + ".loki";
}
else
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Invalid mapping for name = " + request.name + ", specifies non-existent user with id = " + std::to_string(mapping.user_id);
return false;
entry.value = record.mapping.value;
}
entry.register_height = record.mapping.register_height;
entry.txid = epee::string_tools::pod_to_hex(record.mapping.txid);
entry.prev_txid = epee::string_tools::pod_to_hex(record.mapping.prev_txid);
}
}
}
@ -3408,7 +3411,18 @@ namespace cryptonote
COMMAND_RPC_GET_LNS_OWNERS_TO_NAMES::response_mapping &mapping = entry.mappings.back();
mapping.type = db_mapping.type;
mapping.name = db_mapping.name;
mapping.pubkey = db_mapping.value;
if (static_cast<lns::mapping_type>(mapping.type) == lns::mapping_type::lokinet)
{
char buf[64] = {};
base32z::encode(db_mapping.value, buf);
mapping.value = std::string(buf) + ".loki";
}
else
{
mapping.value = db_mapping.value;
}
mapping.register_height = db_mapping.register_height;
mapping.txid = epee::string_tools::pod_to_hex(db_mapping.txid);
mapping.prev_txid = epee::string_tools::pod_to_hex(db_mapping.prev_txid);

View File

@ -3416,16 +3416,16 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
};
LOKI_RPC_DOC_INTROSPECT
// Get the name mapping for a Loki Name Service entry. Loki supports mappings
// from the Blockchain, Lokinet, Messenger and custom types.
// Get the name mapping for a Loki Name Service entry. Loki currently supports mappings
// for Session.
struct COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS
{
static size_t const MAX_REQUEST_ENTRIES = 256;
static size_t const MAX_TYPE_REQUEST_ENTRIES = 16;
struct request_entry
{
std::string name; // The name to resolve to a public key via Loki Name Service
std::vector<uint16_t> types; // [0-2] for Blockchain, Lokinet and Messenger and [65-65536] for custom types, you may request up to 16 types
std::string name; // The name to resolve to a public key via Loki Name Service
std::vector<uint16_t> types; // Set 0 for Session. In future updates more mapping types will be available.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(name)
KV_SERIALIZE(types)
@ -3442,18 +3442,18 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
struct response_entry
{
uint64_t entry_index; // The index in request_entry's `entries` array that was resolved via Loki Name Service
uint16_t type; // The type of Loki Name Service entry that the owner owns.
std::string owner; // The ed25519 public key that purchased the Loki Name Service entry.
std::string pubkey; // The public key that was resolved from the given name
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain
std::string txid; // The txid of who purchased the mapping (only applicable to Lokinet and if the Lokinet entry previously existed), null hash if not applicable
std::string prev_txid; // The previous txid that purchased the mapping (only applicable to Lokinet and if the Lokinet entry previously existed), null hash if not applicable
uint64_t entry_index; // The index in request_entry's `entries` array that was resolved via Loki Name Service.
uint16_t type; // The type of Loki Name Service entry that the owner owns.
std::string owner; // The ed25519 public key that purchased the Loki Name Service entry.
std::string value; // The value that the name maps to.
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain.
std::string txid; // The txid of who purchased the mapping, null hash if not applicable.
std::string prev_txid; // The previous txid that purchased the mapping, null hash if not applicable.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(entry_index)
KV_SERIALIZE(type)
KV_SERIALIZE(owner)
KV_SERIALIZE(pubkey)
KV_SERIALIZE(value)
KV_SERIALIZE(register_height)
KV_SERIALIZE(txid)
KV_SERIALIZE(prev_txid)
@ -3472,9 +3472,9 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
};
LOKI_RPC_DOC_INTROSPECT
// Get all the name mappings for the queried owner. The owner should a ED25519
// public key, by default this is the purchaser's wallet spend key used to
// seed an ED25519 key.
// Get all the name mappings for the queried owner. The owner should be
// a ed25519 public key; by default this is the public key of an ed25519
// keypair derived using the wallet's secret spend key as the seed value.
struct COMMAND_RPC_GET_LNS_OWNERS_TO_NAMES
{
static size_t const MAX_REQUEST_ENTRIES = 256;
@ -3488,16 +3488,16 @@ constexpr char const CORE_RPC_STATUS_TX_LONG_POLL_MAX_CONNECTIONS[] = "Daemon ma
struct response_mapping
{
uint16_t type; // The cateogry the Loki Name Service entry belongs to (blockchain = 0, lokinet = 1, messenger = 2, otherwise custom)
uint16_t type; // The category the Loki Name Service entry belongs to, currently only Session whose value is 0.
std::string name; // The ed25519 public key that purchased the Loki Name Service entry.
std::string pubkey; // The public key that the name maps to.
std::string value; // The value that the name maps to
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain.
std::string txid; // The height that this Loki Name Service entry was purchased on the Blockchain.
std::string prev_txid; // The previous txid that purchased the mapping (only applicable to Lokinet and if the Lokinet entry previously existed), null hash if not applicable
std::string txid; // The txid of who purchases the mapping, null hash if not applicable
std::string prev_txid; // The previous txid that purchased the mapping, null hash if not applicable.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type)
KV_SERIALIZE(name)
KV_SERIALIZE(pubkey)
KV_SERIALIZE(value)
KV_SERIALIZE(txid)
KV_SERIALIZE(prev_txid)
END_KV_SERIALIZE_MAP()

View File

@ -57,6 +57,7 @@
#include "common/dns_utils.h"
#include "common/base58.h"
#include "common/scoped_message_writer.h"
#include "common/hex.h"
#include "common/loki_integration_test_hooks.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "cryptonote_core/service_node_voting.h"
@ -267,8 +268,8 @@ namespace
const char* USAGE_STAKE("stake [index=<N1>[,<N2>,...]] [<priority>] <service node pubkey> <amount|percent%>");
const char* USAGE_REQUEST_STAKE_UNLOCK("request_stake_unlock <service_node_pubkey>");
const char* USAGE_PRINT_LOCKED_STAKES("print_locked_stakes");
const char* USAGE_BUY_LNS_MAPPING("buy_lns_mapping [index=<N1>[,<N2>,...]] [<priority>] [owner] (blockchain|lokinet|messenger|<custom_type_as_number>) \"<name>\" <value>");
const char* USAGE_PRINT_LNS_OWNERS_TO_NAMES("print_lns_owners_to_names [<64 hex character ed25519 key>]");
const char* USAGE_BUY_LNS_MAPPING("buy_lns_mapping [index=<N1>[,<N2>,...]] [<priority>] [owner] \"<name>\" <value>");
const char* USAGE_PRINT_LNS_OWNERS_TO_NAMES("print_lns_owners_to_names [<64 hex character ed25519 public key>]");
const char* USAGE_PRINT_LNS_NAME_TO_OWNERS("print_lns_name_to_owners [type=<N1|all>[,<N2>...]] \"name\"");
#if defined (LOKI_ENABLE_INTEGRATION_TEST_HOOKS)
@ -3217,12 +3218,11 @@ simple_wallet::simple_wallet()
tr(USAGE_PRINT_LOCKED_STAKES),
tr("Print stakes currently locked on the Service Node network"));
std::stringstream stream;
stream << "Buy a Loki Name Service mapping. Specifying `owner` is optional and defaults to the purchasing wallet if empty or not specified. The `owner` is an ED25519 public key, by default derived from the wallet's spend key. You are able to purchase the following mappings\n\n";
stream << "Blockchain: (max: " << lns::BLOCKCHAIN_NAME_MAX << " bytes) map a human readable name to a wallet address\n";
stream << "Lokinet: (max: " << lns::LOKINET_DOMAIN_NAME_MAX << " bytes) map a human readable domain name to a <public_key>.loki address on Lokinet\n";
stream << "Messenger: (max: " << lns::MESSENGER_DISPLAY_NAME_MAX << " bytes) map a human readable name to a messenger public key for Loki Messenger\n";
stream << "Custom: (max: " << lns::GENERIC_NAME_MAX << " bytes) map a human readable name to an arbitrary integer (note, [0-64] are currently reserved by Loki) in the database for custom applications\n";
stream << "Buy a Loki Name Service mapping. Specifying `owner` is optional and defaults to the purchasing wallet if "
"empty or not specified. The `owner` should be a ed25519 public key; by default this is the public key of "
"an ed25519 keypair derived using the wallet's secret spend key as the seed value. You are currently only "
"able to purchase Session mappings\n\n";
stream << "Session: (max: " << lns::SESSION_DISPLAY_NAME_MAX << " bytes) map a human readable name to a Session public key.\n";
m_cmd_binder.set_handler("buy_lns_mapping",
boost::bind(&simple_wallet::buy_lns_mapping, this, _1),
@ -3237,8 +3237,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("print_lns_name_to_owners",
boost::bind(&simple_wallet::print_lns_name_to_owners, this, _1),
tr(USAGE_PRINT_LNS_NAME_TO_OWNERS),
tr("Query the keys that own the Loki Name Service names, where types can be a number from [0-65536] or, \"blockchain\", \"lokinet\", \"messenger\". If type is ommitted, all loki name protocols will be queried (blockchain, lokinet and messenger only)\n"
"You may only query 1 custom type per invocation."));
tr("Query the ed25519 public keys that own the Loki Name System names."));
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::set_variable(const std::vector<std::string> &args)
@ -5721,23 +5720,6 @@ bool simple_wallet::confirm_and_send_tx(std::vector<cryptonote::address_parse_in
worst_fee_per_byte = fee_per_byte;
}
}
try
{
std::vector<std::pair<uint64_t, uint64_t>> nblocks = m_wallet->estimate_backlog({std::make_pair(worst_fee_per_byte, worst_fee_per_byte)});
if (nblocks.size() != 1)
{
prompt << "Internal error checking for backlog. " << tr("Is this okay anyway?");
}
else
{
if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold())
prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay?")) % nblocks[0].first).str();
}
}
catch (const std::exception &e)
{
prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway?");
}
std::string prompt_str = prompt.str();
if (!prompt_str.empty())
@ -5807,7 +5789,7 @@ bool simple_wallet::confirm_and_send_tx(std::vector<cryptonote::address_parse_in
if (lock_time_in_blocks > 0)
{
float days = lock_time_in_blocks / 720.0f;
float days = lock_time_in_blocks / BLOCKS_EXPECTED_IN_DAYS(1.f);
prompt << boost::format(tr(".\nThis transaction (including %s change) will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)")) % cryptonote::print_money(change) % ((unsigned long long)unlock_block) % days;
}
@ -6105,7 +6087,16 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
}
unlock_block = bc_height + locked_blocks;
}
ptx_vector = m_wallet->create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices);
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
{
fail_msg_writer() << tools::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
return false;
}
loki_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);
if (ptx_vector.empty())
{
@ -6573,7 +6564,6 @@ bool simple_wallet::buy_lns_mapping(const std::vector<std::string>& args)
return true;
}
std::string const &type = local_args[0];
std::string const &value = local_args[local_args.size() - 1];
std::string name;
@ -6591,7 +6581,14 @@ bool simple_wallet::buy_lns_mapping(const std::vector<std::string>& args)
std::vector<tools::wallet2::pending_tx> ptx_vector;
try
{
ptx_vector = m_wallet->create_buy_lns_mapping_tx(type, owner, name, value, &reason, priority, m_current_subaddress_account, subaddr_indices);
ptx_vector = m_wallet->create_buy_lns_mapping_tx(static_cast<uint16_t>(lns::mapping_type::session),
owner,
name,
value,
&reason,
priority,
m_current_subaddress_account,
subaddr_indices);
if (ptx_vector.empty())
{
tools::fail_msg_writer() << reason;
@ -6681,9 +6678,9 @@ bool simple_wallet::print_lns_name_to_owners(const std::vector<std::string>& arg
if (entry.types.empty())
{
entry.types.push_back(static_cast<uint16_t>(lns::mapping_type::blockchain));
entry.types.push_back(static_cast<uint16_t>(lns::mapping_type::wallet));
entry.types.push_back(static_cast<uint16_t>(lns::mapping_type::lokinet));
entry.types.push_back(static_cast<uint16_t>(lns::mapping_type::messenger));
entry.types.push_back(static_cast<uint16_t>(lns::mapping_type::session));
}
boost::optional<std::string> failed;
@ -6732,7 +6729,7 @@ bool simple_wallet::print_lns_owners_to_names(const std::vector<std::string>& ar
for (char c : arg)
{
if (!loki::char_is_hex(c))
if (!hex::char_is_hex(c))
{
fail_msg_writer() << "arg contains a non-hex character = " << c << ", arg = " << arg;
return false;
@ -6765,7 +6762,7 @@ bool simple_wallet::print_lns_owners_to_names(const std::vector<std::string>& ar
}
for (cryptonote::COMMAND_RPC_GET_LNS_OWNERS_TO_NAMES::response_mapping const &mapping : entry.mappings)
tools::msg_writer() << "owner=" << *owner << ", height=" << mapping.register_height << ", name=\"" << mapping.name << "\", value=" << mapping.pubkey;
tools::msg_writer() << "owner=" << *owner << ", height=" << mapping.register_height << ", name=\"" << mapping.name << "\", value=" << mapping.value;
}
return true;
}

View File

@ -163,8 +163,8 @@ namespace cryptonote
bool show_payments(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args);
// lock_time_in_blocks: Only required if making a locked transfer, it should be the lock time specified by the sender
// unlock_block: Only required if making a locked transfer, the block height the transaction will unlock at
// lock_time_in_blocks: Only required if making a locked transfer, only for displaying to the user, it should be the lock time specified by the sender
// unlock_block: Only required if lock_time_in_blocks is specified, only for displaying to the user, the height at which the transfer will unlock
bool confirm_and_send_tx(std::vector<cryptonote::address_parse_info> const &dests, std::vector<tools::wallet2::pending_tx> &ptx_vector, bool blink, uint64_t lock_time_in_blocks = 0, uint64_t unlock_block = 0, bool called_by_mms = false);
bool transfer_main(Transfer transfer_type, const std::vector<std::string> &args, bool called_by_mms);

View File

@ -1516,6 +1516,15 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
de.is_subaddress = info.is_subaddress;
de.is_integrated = info.has_payment_id;
dsts.push_back(de);
cryptonote::loki_construct_tx_params tx_params;
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
{
setStatusError(tools::ERR_MSG_NETWORK_VERSION_QUERY_FAILED);
return transaction;
}
loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, txtype::standard, priority);
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
adjusted_priority,
extra, subaddr_account, subaddr_indices);

View File

@ -262,12 +262,6 @@ static bool check_invoke(bool r, T &response, boost::optional<std::string> &fail
return false;
}
if (response.status == CORE_RPC_STATUS_BUSY)
{
failed = response.status;
return false;
}
if (response.status != CORE_RPC_STATUS_OK)
{
failed = response.status;

View File

@ -7671,7 +7671,8 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
}
return priority;
}
loki_construct_tx_params wallet2::construct_params(uint8_t hf_version, txtype tx_type, uint32_t priority)
loki_construct_tx_params wallet2::construct_params(uint8_t hf_version, txtype tx_type, uint32_t priority, lns::burn_type lns_burn_type)
{
loki_construct_tx_params tx_params;
tx_params.hf_version = hf_version;
@ -7680,7 +7681,7 @@ loki_construct_tx_params wallet2::construct_params(uint8_t hf_version, txtype tx
if (tx_type == txtype::loki_name_system)
{
assert(priority != tools::tx_priority_blink);
tx_params.burn_fixed = lns::burn_requirement_in_atomic_loki(hf_version);
tx_params.burn_fixed = lns::burn_requirement_in_atomic_loki(hf_version, lns_burn_type);
}
else if (priority == tools::tx_priority_blink)
{
@ -7951,12 +7952,6 @@ bool wallet2::is_output_blackballed(const std::pair<uint64_t, uint64_t> &output)
catch (const std::exception &e) { return false; }
}
static const char *ERR_MSG_NETWORK_VERSION_QUERY_FAILED = tr("Could not query the current network version, try later");
static const char *ERR_MSG_NETWORK_HEIGHT_QUERY_FAILED = tr("Could not query the current network block height, try later: ");
static const char *ERR_MSG_SERVICE_NODE_LIST_QUERY_FAILED = tr("Failed to query daemon for service node list");
static const char *ERR_MSG_TOO_MANY_TXS_CONSTRUCTED = tr("Constructed too many transations, please sweep_all first");
static const char *ERR_MSG_EXCEPTION_THROWN = tr("Exception thrown, staking process could not be completed: ");
wallet2::stake_result wallet2::check_stake_allowed(const crypto::public_key& sn_key, const cryptonote::address_parse_info& addr_info, uint64_t& amount, double fraction)
{
wallet2::stake_result result = {};
@ -8165,7 +8160,8 @@ wallet2::stake_result wallet2::create_stake_tx(const crypto::public_key& service
return result;
}
auto ptx_vector = create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, unlock_at_block, priority, extra, subaddr_account, subaddr_indices, txtype::stake);
loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, txtype::stake, priority);
auto ptx_vector = create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, unlock_at_block, priority, extra, subaddr_account, subaddr_indices, tx_params);
if (ptx_vector.size() == 1)
{
result.status = stake_result_status::success;
@ -8401,7 +8397,8 @@ wallet2::register_service_node_result wallet2::create_register_service_node_tx(c
cryptonote::address_parse_info dest = {};
dest.address = address;
auto ptx_vector = create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, 0 /* unlock_time */, priority, extra, subaddr_account, subaddr_indices, txtype::stake);
loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, txtype::stake, priority);
auto ptx_vector = create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, 0 /* unlock_time */, priority, extra, subaddr_account, subaddr_indices, tx_params);
if (ptx_vector.size() == 1)
{
result.status = register_service_node_result_status::success;
@ -8554,11 +8551,11 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
uint32_t account_index,
std::set<uint32_t> subaddr_indices)
{
if (!lns::validate_lns_name(type, name.data(), name.size(), reason))
if (!lns::validate_lns_name(type, name, reason))
return {};
lns::lns_value value_blob;
if (!lns::validate_lns_value(nettype(), type, value.data(), value.size(), &value_blob, reason))
if (!lns::validate_lns_value(nettype(), type, value, &value_blob, reason))
return {};
if (priority == tools::tx_priority_blink)
@ -8583,7 +8580,6 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
}
crypto::hash prev_txid = crypto::null_hash;
if (type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
std::vector<cryptonote::COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::request_entry> request = {};
{
@ -8597,7 +8593,7 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
std::vector<cryptonote::COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::response_entry> response = get_lns_names_to_owners(request, failed);
if (failed)
{
if (reason) *reason = "Failed to query previous owner for lokinet entry, reason=" + *failed;
if (reason) *reason = "Failed to query previous owner for LNS entry, reason=" + *failed;
return {};
}
@ -8616,10 +8612,18 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
}
}
tx_extra_loki_name_system entry(pkey, type, name, value, prev_txid);
boost::optional<uint8_t> hf_version = get_hard_fork_version();
if (!hf_version)
{
if (reason) *reason = ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
return {};
}
std::vector<uint8_t> extra;
tx_extra_loki_name_system entry(pkey, type, name, value, prev_txid);
add_loki_name_system_to_tx_extra(extra, entry);
loki_construct_tx_params tx_params = wallet2::construct_params(*hf_version, txtype::loki_name_system, priority, lns::mapping_type_to_burn_type(static_cast<lns::mapping_type>(type)));
auto result = create_transactions_2({} /*dests*/,
CRYPTONOTE_DEFAULT_TX_MIXIN,
0 /*unlock_at_block*/,
@ -8627,7 +8631,7 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
extra,
account_index,
subaddr_indices,
txtype::loki_name_system);
tx_params);
return result;
}
@ -10354,7 +10358,7 @@ static constexpr uint64_t BURN_FEE_PLACEHOLDER = (1ULL << (6*7)) - 1;
// This system allows for sending (almost) the entire balance, since it does
// not generate spurious change in all txes, thus decreasing the instantaneous
// usable balance.
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra_base, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, cryptonote::txtype tx_type)
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra_base, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, loki_construct_tx_params &tx_params)
{
//ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device();
@ -10362,7 +10366,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
hw::reset_mode rst(hwdev);
auto original_dsts = dsts;
if (tx_type == txtype::loki_name_system)
if (tx_params.tx_type == txtype::loki_name_system)
{
THROW_WALLET_EXCEPTION_IF(dsts.size() != 0, error::wallet_internal_error, "loki name system txs must not have any destinations set, has: " + std::to_string(dsts.size()));
dsts.emplace_back(0, account_public_address{} /*address*/, false /*is_subaddress*/); // NOTE: Create a dummy dest that gets repurposed into the change output.
@ -10425,18 +10429,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
uint64_t fixed_fee = 0;
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
boost::optional<uint8_t> hf_version = get_hard_fork_version();
THROW_WALLET_EXCEPTION_IF(!hf_version, error::get_hard_fork_version_error, "Failed to query current hard fork version");
loki_construct_tx_params loki_tx_params = tools::wallet2::construct_params(*hf_version, tx_type, priority);
uint64_t burn_fixed = 0, burn_percent = 0;
// Swap these out because we don't want them present for building intermediate temporary tx
// calculations (which we don't actually use); we'll set them again at the end before we build the
// real transactions.
std::swap(burn_fixed, loki_tx_params.burn_fixed);
std::swap(burn_percent, loki_tx_params.burn_percent);
std::swap(burn_fixed, tx_params.burn_fixed);
std::swap(burn_percent, tx_params.burn_percent);
bool burning = burn_fixed || burn_percent;
THROW_WALLET_EXCEPTION_IF(burning && loki_tx_params.hf_version < HF_VERSION_FEE_BURNING, error::wallet_internal_error, "cannot construct transaction: cannot burn amounts under the current hard fork");
THROW_WALLET_EXCEPTION_IF(burning && tx_params.hf_version < HF_VERSION_FEE_BURNING, error::wallet_internal_error, "cannot construct transaction: cannot burn amounts under the current hard fork");
std::vector<uint8_t> extra_plus; // Copy and modified from input if modification needed
const std::vector<uint8_t> &extra = burning ? extra_plus : extra_base;
if (burning)
@ -10455,14 +10455,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
needed_money = 0;
for(auto& dt: dsts)
{
THROW_WALLET_EXCEPTION_IF(0 == dt.amount && (tx_type != txtype::loki_name_system), error::zero_destination);
THROW_WALLET_EXCEPTION_IF(0 == dt.amount && (tx_params.tx_type != txtype::loki_name_system), error::zero_destination);
needed_money += dt.amount;
LOG_PRINT_L2("transfer: adding " << print_money(dt.amount) << ", for a total of " << print_money (needed_money));
THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, 0, m_nettype);
}
// throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF(needed_money == 0 && (tx_type != txtype::loki_name_system), error::zero_destination);
THROW_WALLET_EXCEPTION_IF(needed_money == 0 && (tx_params.tx_type != txtype::loki_name_system), error::zero_destination);
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account);
@ -10476,7 +10476,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// early out if we know we can't make it anyway
// we could also check for being within FEE_PER_KB, but if the fee calculation
// ever changes, this might be missed, so let this go through
const uint64_t num_outputs = tx_type == txtype::loki_name_system ? 1 : 2;
const uint64_t num_outputs = tx_params.tx_type == txtype::loki_name_system ? 1 : 2;
{
uint64_t min_fee = (
base_fee.first * estimate_rct_tx_size(1, fake_outs_count, num_outputs, extra.size()) +
@ -10653,7 +10653,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
idx = pop_back(preferred_inputs);
pop_if_present(*unused_transfers_indices, idx);
pop_if_present(*unused_dust_indices, idx);
} else if ((dsts.empty() || (dsts[0].amount == 0 && tx_type != txtype::loki_name_system)) && !adding_fee) {
} else if ((dsts.empty() || (dsts[0].amount == 0 && tx_params.tx_type != txtype::loki_name_system)) && !adding_fee) {
// NOTE: A LNS tx sets dsts[0].amount to 0, but this branch is for the
// 2 inputs/2 outputs. We only have 1 output as LNS transactions are
// distinguishable, so we actually want the last branch which uses unused
@ -10771,7 +10771,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
tx.selected_transfers.size() << " inputs");
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config, loki_tx_params);
test_tx, test_ptx, rct_config, tx_params);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
needed_fee = calculate_fee(test_ptx.tx, txBlob.size(), base_fee, fee_percent, fixed_fee, fee_quantization_mask);
available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
@ -10810,7 +10810,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee));
while (needed_fee > test_ptx.fee) {
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config, loki_tx_params);
test_tx, test_ptx, rct_config, tx_params);
txBlob = t_serializable_object_to_blob(test_ptx.tx);
needed_fee = calculate_fee(test_ptx.tx, txBlob.size(), base_fee, fee_percent, fixed_fee, fee_quantization_mask);
LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) <<
@ -10872,9 +10872,9 @@ skip_tx:
// fee percent)
if (burning)
{
loki_tx_params.burn_fixed = burn_fixed + tx.needed_fee * burn_percent / fee_percent;
tx_params.burn_fixed = burn_fixed + tx.needed_fee * burn_percent / fee_percent;
// Make sure we can't enlarge the tx because that could make it invalid:
THROW_WALLET_EXCEPTION_IF(loki_tx_params.burn_fixed > BURN_FEE_PLACEHOLDER, error::wallet_internal_error, "attempt to burn a larger amount than is internally supported");
THROW_WALLET_EXCEPTION_IF(tx_params.burn_fixed > BURN_FEE_PLACEHOLDER, error::wallet_internal_error, "attempt to burn a larger amount than is internally supported");
}
cryptonote::transaction test_tx;
@ -10889,7 +10889,7 @@ skip_tx:
test_tx, /* OUT cryptonote::transaction& tx, */
test_ptx, /* OUT cryptonote::transaction& tx, */
rct_config,
loki_tx_params);
tx_params);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
tx.tx = test_tx;
tx.ptx = test_ptx;

View File

@ -51,6 +51,7 @@
#include "rpc/core_rpc_server_commands_defs.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "cryptonote_core/loki_name_system.h"
#include "common/unordered_containers_boost_serialization.h"
#include "common/util.h"
#include "crypto/chacha.h"
@ -80,6 +81,12 @@ class wallet_accessor_test;
LOKI_RPC_DOC_INTROSPECT
namespace tools
{
static const char *ERR_MSG_NETWORK_VERSION_QUERY_FAILED = tr("Could not query the current network version, try later");
static const char *ERR_MSG_NETWORK_HEIGHT_QUERY_FAILED = tr("Could not query the current network block height, try later: ");
static const char *ERR_MSG_SERVICE_NODE_LIST_QUERY_FAILED = tr("Failed to query daemon for service node list");
static const char *ERR_MSG_TOO_MANY_TXS_CONSTRUCTED = tr("Constructed too many transations, please sweep_all first");
static const char *ERR_MSG_EXCEPTION_THROWN = tr("Exception thrown, staking process could not be completed: ");
class ringdb;
class wallet2;
class Notify;
@ -962,7 +969,7 @@ private:
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const;
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, cryptonote::txtype tx_type = cryptonote::txtype::standard); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra_base, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, cryptonote::loki_construct_tx_params &tx_params);
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, cryptonote::txtype tx_type = cryptonote::txtype::standard);
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, cryptonote::txtype tx_type = cryptonote::txtype::standard);
@ -1389,8 +1396,9 @@ private:
uint64_t adjust_mixin(uint64_t mixin) const;
uint32_t adjust_priority(uint32_t priority);
// params constructor, accumulates the burn amounts if the priority is a blink and, or a lns tx
static cryptonote::loki_construct_tx_params construct_params(uint8_t hf_version, cryptonote::txtype tx_type, uint32_t priority);
// params constructor, accumulates the burn amounts if the priority is
// a blink and, or a lns tx. If it is a blink TX, lns_burn_type is ignored.
static cryptonote::loki_construct_tx_params construct_params(uint8_t hf_version, cryptonote::txtype tx_type, uint32_t priority, lns::burn_type lns_burn_type = lns::burn_type::none);
bool is_unattended() const { return m_unattended; }

View File

@ -863,7 +863,16 @@ namespace tools
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
if (req.blink) priority = tools::tx_priority_blink;
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
{
er.code = WALLET_RPC_ERROR_CODE_HF_QUERY_FAILED;
er.message = tools::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
return false;
}
cryptonote::loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, cryptonote::txtype::standard, priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, tx_params);
if (ptx_vector.empty())
{
@ -916,8 +925,18 @@ namespace tools
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
if (req.blink) priority = tools::tx_priority_blink;
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
{
er.code = WALLET_RPC_ERROR_CODE_HF_QUERY_FAILED;
er.message = tools::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
return false;
}
cryptonote::loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, cryptonote::txtype::standard, priority);
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, tx_params);
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, req.blink,

View File

@ -2870,10 +2870,10 @@ namespace wallet_rpc
{
struct request_t
{
std::string type; // The mapping type, either "blockchain", "lokinet", "messenger" or if custom, a value between [65-65536] (0-2 map to the predefined mappings listed earlier).
std::string type; // The mapping type, either "blockchain", "lokinet", "session" or if custom, a value between [65-65536] (0-2 map to the predefined mappings listed earlier).
std::string owner; // (Optional): The owner of the mapping (wallet spend key as ed25519 public key in hex). For Lokinet, the owner has the ability to renew the Loki Name Service entry. By default/if field is empty, it is derived from the wallet purchasing the LNS 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 wallets: name -> wallet address. For messenger: display name -> messenger public key. For Lokinet: name -> domain name).
std::string value; // The value that the name maps to via Loki Name Service, (i.e. For wallets: name -> wallet address. For session: display name -> session public key. 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)

View File

@ -78,3 +78,4 @@
// Loki:
#define WALLET_RPC_ERROR_CODE_BLINK_FAILED -1000
#define WALLET_RPC_ERROR_CODE_HF_QUERY_FAILED -1001

View File

@ -521,14 +521,13 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(crypton
cryptonote::block const &head = top().block;
uint64_t new_height = get_block_height(top().block) + 1;
uint8_t new_hf_version = get_hf_version_at(new_height);
if (burn == LNS_AUTO_BURN) burn = lns::burn_requirement_in_atomic_loki(new_hf_version);
if (burn == LNS_AUTO_BURN)
burn = lns::burn_requirement_in_atomic_loki(new_hf_version,
lns::mapping_type_to_burn_type(static_cast<lns::mapping_type>(type)));
crypto::hash prev_txid = crypto::null_hash;
if (type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
if (lns::mapping_record mapping = lns_db_.get_mapping(type, name))
prev_txid = mapping.txid;
}
if (lns::mapping_record mapping = lns_db_.get_mapping(type, name))
prev_txid = mapping.txid;
std::vector<uint8_t> extra;
cryptonote::tx_extra_loki_name_system data(pkey, type, name, value, prev_txid);

View File

@ -126,6 +126,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(loki_name_system_disallow_reserved_type);
GENERATE_AND_PLAY(loki_name_system_expiration);
GENERATE_AND_PLAY(loki_name_system_get_mappings_by_user);
GENERATE_AND_PLAY(loki_name_system_get_mapping_by_name_and_type);
GENERATE_AND_PLAY(loki_name_system_handles_duplicate_in_lns_db);
GENERATE_AND_PLAY(loki_name_system_handles_duplicate_in_tx_pool);
GENERATE_AND_PLAY(loki_name_system_invalid_tx_extra_params);

View File

@ -1003,14 +1003,14 @@ bool loki_name_system_disallow_reserved_type::generate(std::vector<test_event_en
gen.add_mined_money_unlock_blocks();
std::string mapping_value = "asdf";
cryptonote::transaction tx1 = gen.create_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::start_reserved), mapping_value, "FriendlyName");
cryptonote::transaction tx1 = gen.create_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::start_unusable_range), mapping_value, "FriendlyName");
gen.add_tx(tx1, false /*can_be_added_to_blockchain*/, "Can't create a LNS TX that requests a LNS type that is unused but reserved by the protocol");
return true;
}
static bool lns_mapping_type_enabled(lns::mapping_type type)
{
bool result = !(type >= lns::mapping_type::start_reserved && type <= lns::mapping_type::end_reserved);
bool result = !(type >= lns::mapping_type::start_unusable_range && type <= lns::mapping_type::end_unusable_range);
return result;
}
@ -1018,12 +1018,12 @@ struct lns_keys_t
{
crypto::ed25519_public_key ed_key;
crypto::ed25519_secret_key ed_skey;
std::string blockchain_value; // NOTE: this field is the binary (value) part of the name -> (value) mapping
std::string wallet_value; // NOTE: this field is the binary (value) part of the name -> (value) mapping
std::string lokinet_value;
std::string messenger_value;
std::string session_value;
std::string messenger_value_hex; // NOTE: likewise, but represented in hex, except, for blockchain, which is the cryptonote account address
std::string blockchain_value_hex;
std::string session_value_hex; // NOTE: likewise, but represented in hex, except, for blockchain, which is the cryptonote account address
std::string wallet_value_hex;
std::string lokinet_value_hex;
};
@ -1032,16 +1032,16 @@ static lns_keys_t make_lns_keys(cryptonote::account_base const &src)
lns_keys_t result = {};
crypto_sign_ed25519_seed_keypair(result.ed_key.data, result.ed_skey.data, reinterpret_cast<const unsigned char *>(src.get_keys().m_spend_secret_key.data));
char messenger_value[lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH] = {};
messenger_value[0] = 5; // prefix with 0x05
memcpy(messenger_value + 1, &result.ed_key, sizeof(result.ed_key));
char session_value[lns::SESSION_PUBLIC_KEY_BINARY_LENGTH] = {};
session_value[0] = 5; // prefix with 0x05
memcpy(session_value + 1, &result.ed_key, sizeof(result.ed_key));
result.messenger_value = std::string(messenger_value, sizeof(messenger_value));
result.blockchain_value = std::string((char *)&src.get_keys().m_account_address, sizeof(src.get_keys().m_account_address));
result.session_value = std::string(session_value, sizeof(session_value));
result.wallet_value = std::string((char *)&src.get_keys().m_account_address, sizeof(src.get_keys().m_account_address));
result.lokinet_value = std::string((char *)result.ed_key.data, sizeof(result.ed_key.data));
result.messenger_value_hex = epee::string_tools::pod_to_hex(messenger_value);
result.blockchain_value_hex = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false /*subaddress*/, src.get_keys().m_account_address);
result.session_value_hex = epee::string_tools::pod_to_hex(session_value);
result.wallet_value_hex = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false /*subaddress*/, src.get_keys().m_account_address);
result.lokinet_value_hex = epee::string_tools::pod_to_hex(result.ed_key);
return result;
}
@ -1060,7 +1060,7 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
lns_keys_t miner_key = make_lns_keys(miner);
if (lns_mapping_type_enabled(lns::mapping_type::lokinet))
{
char const name[] = "mydomain.loki";
std::string const name = "mydomain.loki";
cryptonote::transaction tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.lokinet_value, name);
gen.create_and_add_next_block({tx});
@ -1077,10 +1077,10 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
CHECK_EQ(user.id, 1);
CHECK_EQ(miner_key.ed_key, user.key);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name, loki::char_count(name));
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name);
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::lokinet));
CHECK_EQ(mappings.name, std::string(name));
CHECK_EQ(mappings.name, name);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.user_id, user.id);
@ -1101,11 +1101,11 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
CHECK_EQ(user.id, 1);
CHECK_EQ(miner_key.ed_key, user.key);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name, loki::char_count(name));
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name);
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.active(cryptonote::FAKECHAIN, blockchain_height), false);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::lokinet));
CHECK_EQ(mappings.name, std::string(name));
CHECK_EQ(mappings.name, name);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.user_id, user.id);
@ -1135,14 +1135,14 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
}
lns_keys_t bob_key = make_lns_keys(bob);
std::string messenger_name1 = "MyName";
std::string messenger_name2 = "AnotherName";
std::string session_name1 = "MyName";
std::string session_name2 = "AnotherName";
{
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name1);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name2, &bob_key.ed_key);
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name1);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name2, &bob_key.ed_key);
gen.create_and_add_next_block({tx1, tx2});
}
uint64_t messenger_height = gen.height();
uint64_t session_height = gen.height();
// NOTE: Register some Lokinet names
std::string lokinet_name1 = "lorem.loki";
@ -1160,12 +1160,12 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
// NOTE: Register some wallet names
std::string wallet_name1 = "Wallet1";
std::string wallet_name2 = "Wallet2";
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
if (lns_mapping_type_enabled(lns::mapping_type::wallet))
{
{
std::string bob_addr = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false, bob.get_keys().m_account_address);
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::blockchain), bob_key.blockchain_value, wallet_name1);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::blockchain), bob_key.blockchain_value, wallet_name2, &bob_key.ed_key);
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::wallet), bob_key.wallet_value, wallet_name1);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::wallet), bob_key.wallet_value, wallet_name2, &bob_key.ed_key);
gen.create_and_add_next_block({tx1, tx2});
}
}
@ -1173,7 +1173,7 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
loki_register_callback(events, "check_lns_entries", [&events, bob_key,
wallet_height, wallet_name1, wallet_name2,
messenger_height, messenger_name1, messenger_name2,
session_height, session_name1, session_name2,
lokinet_height, lokinet_name1, lokinet_name2
](cryptonote::core &c, size_t ev_index)
{
@ -1182,21 +1182,21 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
std::vector<lns::mapping_record> records = lns_db.get_mappings_by_user(bob_key.ed_key);
size_t expected_size = 0;
if (lns_mapping_type_enabled(lns::mapping_type::messenger)) expected_size += 2;
if (lns_mapping_type_enabled(lns::mapping_type::blockchain)) expected_size += 2;
if (lns_mapping_type_enabled(lns::mapping_type::session)) expected_size += 2;
if (lns_mapping_type_enabled(lns::mapping_type::wallet)) expected_size += 2;
if (lns_mapping_type_enabled(lns::mapping_type::lokinet)) expected_size += 2;
CHECK_EQ(records.size(), expected_size);
if (lns_mapping_type_enabled(lns::mapping_type::messenger))
if (lns_mapping_type_enabled(lns::mapping_type::session))
{
CHECK_EQ(records[0].name, messenger_name1);
CHECK_EQ(records[1].name, messenger_name2);
CHECK_EQ(records[0].register_height, messenger_height);
CHECK_EQ(records[1].register_height, messenger_height);
CHECK_EQ(records[0].value, bob_key.messenger_value);
CHECK_EQ(records[1].value, bob_key.messenger_value);
CHECK_EQ(records[0].type, static_cast<uint16_t>(lns::mapping_type::messenger));
CHECK_EQ(records[1].type, static_cast<uint16_t>(lns::mapping_type::messenger));
CHECK_EQ(records[0].name, session_name1);
CHECK_EQ(records[1].name, session_name2);
CHECK_EQ(records[0].register_height, session_height);
CHECK_EQ(records[1].register_height, session_height);
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[1].value, bob_key.session_value);
CHECK_EQ(records[0].type, static_cast<uint16_t>(lns::mapping_type::session));
CHECK_EQ(records[1].type, static_cast<uint16_t>(lns::mapping_type::session));
}
if (lns_mapping_type_enabled(lns::mapping_type::lokinet))
@ -1211,16 +1211,16 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
CHECK_EQ(records[3].type, static_cast<uint16_t>(lns::mapping_type::lokinet));
}
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
if (lns_mapping_type_enabled(lns::mapping_type::wallet))
{
CHECK_EQ(records[4].name, wallet_name1);
CHECK_EQ(records[5].name, wallet_name2);
CHECK_EQ(records[4].register_height, wallet_height);
CHECK_EQ(records[5].register_height, wallet_height);
CHECK_EQ(records[4].value, bob_key.blockchain_value);
CHECK_EQ(records[5].value, bob_key.blockchain_value);
CHECK_EQ(records[4].type, static_cast<uint16_t>(lns::mapping_type::blockchain));
CHECK_EQ(records[5].type, static_cast<uint16_t>(lns::mapping_type::blockchain));
CHECK_EQ(records[4].value, bob_key.wallet_value);
CHECK_EQ(records[5].value, bob_key.wallet_value);
CHECK_EQ(records[4].type, static_cast<uint16_t>(lns::mapping_type::wallet));
CHECK_EQ(records[5].type, static_cast<uint16_t>(lns::mapping_type::wallet));
}
return true;
});
@ -1228,6 +1228,53 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
return true;
}
bool loki_name_system_get_mapping_by_name_and_type::generate(std::vector<test_event_entry> &events)
{
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
loki_chain_generator gen(events, hard_forks);
cryptonote::account_base miner = gen.first_miner_;
cryptonote::account_base bob = gen.add_account();
gen.add_blocks_until_version(hard_forks.back().first);
// NOTE: Fund Bob's wallet
{
gen.add_n_blocks(10); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
cryptonote::transaction transfer = gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(400));
gen.create_and_add_next_block({transfer});
gen.add_mined_money_unlock_blocks();
}
lns_keys_t bob_key = make_lns_keys(bob);
std::string session_name1 = "MyName";
crypto::hash session_tx_hash;
{
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name1);
session_tx_hash = cryptonote::get_transaction_hash(tx1);
gen.create_and_add_next_block({tx1});
}
uint64_t session_height = gen.height();
loki_register_callback(events, "check_lns_entries", [&events, bob_key, session_height, session_name1, session_tx_hash](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_lns_entries");
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
lns::mapping_and_user_record record = lns_db.get_mapping_by_name_and_type(lns::mapping_type::session, session_name1);
CHECK_EQ(record.mapping.type, static_cast<uint16_t>(lns::mapping_type::session));
CHECK_EQ(record.mapping.name, session_name1);
CHECK_EQ(record.mapping.value, bob_key.session_value);
CHECK_EQ(record.mapping.register_height, session_height);
CHECK_EQ(record.mapping.prev_txid, crypto::null_hash);
CHECK_EQ(record.mapping.txid, session_tx_hash);
CHECK_EQ(record.owner, bob_key.ed_key);
return true;
});
return true;
}
bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_event_entry> &events)
{
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
@ -1246,16 +1293,16 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
lns_keys_t miner_key = make_lns_keys(miner);
lns_keys_t bob_key = make_lns_keys(bob);
std::string messenger_name = "myfriendlydisplayname.loki";
std::string session_name = "myfriendlydisplayname.loki";
uint16_t custom_type = 3928;
{
// NOTE: Allow duplicates with the same name but different type
cryptonote::transaction bar = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.messenger_value, messenger_name);
cryptonote::transaction bar = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name);
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.session_value, session_name);
if (lns_mapping_type_enabled(lns::mapping_type::lokinet))
{
cryptonote::transaction bar3 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.lokinet_value, messenger_name);
cryptonote::transaction bar3 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.lokinet_value, session_name);
gen.create_and_add_next_block({bar, bar2, bar3});
}
else
@ -1266,11 +1313,11 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
uint64_t height_of_lns_entry = gen.height();
{
cryptonote::transaction bar6 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
cryptonote::transaction bar6 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name);
gen.add_tx(bar6, false /*can_be_added_to_blockchain*/, "Duplicate name requested by new owner: original already exists in lns db");
}
loki_register_callback(events, "check_lns_entries", [&events, height_of_lns_entry, miner_key, bob_key, messenger_name, custom_type](cryptonote::core &c, size_t ev_index)
loki_register_callback(events, "check_lns_entries", [&events, height_of_lns_entry, miner_key, bob_key, session_name, custom_type](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_lns_entries");
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
@ -1280,30 +1327,30 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
CHECK_EQ(user.id, 1);
CHECK_EQ(miner_key.ed_key, user.key);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::messenger), messenger_name);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::session), session_name);
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::messenger));
CHECK_EQ(mappings.name, messenger_name);
CHECK_EQ(mappings.value, bob_key.messenger_value);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::session));
CHECK_EQ(mappings.name, session_name);
CHECK_EQ(mappings.value, bob_key.session_value);
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.user_id, user.id);
if (lns_mapping_type_enabled(lns::mapping_type::lokinet))
{
lns::mapping_record mappings2 = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), messenger_name);
lns::mapping_record mappings2 = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), session_name);
CHECK_EQ(mappings2.loaded, true);
CHECK_EQ(mappings2.type, static_cast<uint16_t>(lns::mapping_type::lokinet));
CHECK_EQ(mappings2.name, messenger_name);
CHECK_EQ(mappings2.name, session_name);
CHECK_EQ(mappings2.value, miner_key.lokinet_value);
CHECK_EQ(mappings2.register_height, height_of_lns_entry);
CHECK_EQ(mappings2.user_id, user.id);
}
lns::mapping_record mappings3 = lns_db.get_mapping(custom_type, messenger_name);
lns::mapping_record mappings3 = lns_db.get_mapping(custom_type, session_name);
CHECK_EQ(mappings3.loaded, true);
CHECK_EQ(mappings3.type, custom_type);
CHECK_EQ(mappings3.name, messenger_name);
CHECK_EQ(mappings3.value, bob_key.messenger_value);
CHECK_EQ(mappings3.name, session_name);
CHECK_EQ(mappings3.value, bob_key.session_value);
CHECK_EQ(mappings3.register_height, height_of_lns_entry);
CHECK_EQ(mappings3.user_id, user.id);
@ -1333,16 +1380,16 @@ bool loki_name_system_handles_duplicate_in_tx_pool::generate(std::vector<test_ev
lns_keys_t miner_key = make_lns_keys(miner);
lns_keys_t bob_key = make_lns_keys(bob);
std::string messenger_name = "myfriendlydisplayname.loki";
std::string session_name = "myfriendlydisplayname.loki";
uint16_t custom_type = 3928;
{
// NOTE: Allow duplicates with the same name but different type
cryptonote::transaction bar = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.messenger_value, messenger_name);
cryptonote::transaction bar = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name);
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.session_value, session_name);
// NOTE: Make duplicate in the TX pool, this should be rejected
cryptonote::transaction bar4 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
cryptonote::transaction bar4 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, session_name);
gen.add_tx(bar4, false /*can_be_added_to_blockchain*/, "Duplicate name requested by new owner: original already exists in tx pool");
}
return true;
@ -1369,7 +1416,9 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
char const *reason) -> void {
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
uint64_t burn_requirement = lns::burn_requirement_in_atomic_loki(new_hf_version);
lns::burn_type burn_type = lns::mapping_type_to_burn_type(static_cast<lns::mapping_type>(data.type));
uint64_t burn_requirement = lns::burn_requirement_in_atomic_loki(new_hf_version, burn_type);
std::vector<uint8_t> extra;
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
@ -1387,16 +1436,16 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
cryptonote::tx_extra_loki_name_system valid_data = {};
valid_data.owner = miner_key.ed_key;
valid_data.type = static_cast<uint16_t>(lns::mapping_type::blockchain);
valid_data.value = miner_key.blockchain_value;
valid_data.type = static_cast<uint16_t>(lns::mapping_type::wallet);
valid_data.value = miner_key.wallet_value;
valid_data.name = "my_lns_name";
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
if (lns_mapping_type_enabled(lns::mapping_type::wallet))
{
// Blockchain name too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = std::string(lns::BLOCKCHAIN_NAME_MAX + 1, 'A');
data.name = std::string(lns::WALLET_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Wallet to name in LNS too long");
}
@ -1455,54 +1504,54 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
}
}
// Messenger value invalid, messenger keys require a 33 byte key where the first byte is a 0x05
// Session value invalid, session keys require a 33 byte key where the first byte is a 0x05
std::stringstream stream;
valid_data.type = static_cast<uint16_t>(lns::mapping_type::messenger);
valid_data.type = static_cast<uint16_t>(lns::mapping_type::session);
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value[0] = 'a';
stream << "(Messenger) Key invalid, not prefixed with 0x05";
stream << "(Session) Key invalid, not prefixed with 0x05";
make_lns_tx_with_custom_extra(gen, events, miner, data, false, stream.str().c_str());
stream.clear();
}
// Messenger should be valid with this key with a 0x05 prefix
valid_data.value = miner_key.messenger_value;
// Session should be valid with this key with a 0x05 prefix
valid_data.value = miner_key.session_value;
{
cryptonote::tx_extra_loki_name_system data = valid_data;
stream << "(Messenger) Key should be valid, prefixed with 0x05: " << miner_key.messenger_value_hex;
stream << "(Session) Key should be valid, prefixed with 0x05: " << miner_key.session_value_hex;
make_lns_tx_with_custom_extra(gen, events, miner, data, true, stream.str().c_str());
stream.clear();
}
// Messenger value too short
// We added valid tx prior, we should update name to avoid conflict names in messenger land and test other invalid params
// Session value too short
// We added valid tx prior, we should update name to avoid conflict names in session land and test other invalid params
valid_data.name = "new_friendly_name";
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH * 2 - 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, value too short");
data.value = std::string(lns::SESSION_PUBLIC_KEY_BINARY_LENGTH * 2 - 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) User id, value too short");
}
// Messenger value too long
// Session value too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH * 2 + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, value too long");
data.value = std::string(lns::SESSION_PUBLIC_KEY_BINARY_LENGTH * 2 + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) User id, value too long");
}
// Messenger name too long
// Session name too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = std::string(lns::MESSENGER_DISPLAY_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, name too long");
data.name = std::string(lns::SESSION_DISPLAY_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) User id, name too long");
}
// Messenger name empty
// Session name empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = {};
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, name too long");
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Session) User id, name too long");
}
// Generic name empty
@ -1564,17 +1613,17 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
uint64_t miner_earliest_renewable_height = 0;
std::string const miner_lokinet_domain1 = "website.loki";
std::string const miner_wallet_name1 = "MyWallet";
std::string const miner_messenger_name1 = "I Like Loki";
std::string const miner_session_name1 = "I Like Loki";
{
// NOTE: Generate and add the (transactions + block) to the blockchain
{
std::vector<cryptonote::transaction> txs;
cryptonote::transaction messenger_tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::messenger), miner_key.messenger_value, miner_messenger_name1);
txs.push_back(messenger_tx);
cryptonote::transaction session_tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::session), miner_key.session_value, miner_session_name1);
txs.push_back(session_tx);
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
if (lns_mapping_type_enabled(lns::mapping_type::wallet))
{
cryptonote::transaction wallet_tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::blockchain), miner_key.blockchain_value, miner_wallet_name1);
cryptonote::transaction wallet_tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::wallet), miner_key.wallet_value, miner_wallet_name1);
txs.push_back(wallet_tx);
}
@ -1595,24 +1644,24 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
miner_earliest_renewable_height = first_lns_height + expiry_blocks - renew_window;
}
loki_register_callback(events, "check_first_lns_entries", [miner_key, miner_messenger_name1, miner_lokinet_domain1, miner_wallet_name1, first_lns_height](cryptonote::core &c, size_t ev_index)
loki_register_callback(events, "check_first_lns_entries", [miner_key, miner_session_name1, miner_lokinet_domain1, miner_wallet_name1, first_lns_height](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_first_lns_entries");
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
std::vector<lns::mapping_record> records = lns_db.get_mappings_by_user(miner_key.ed_key);
size_t expected_size = 1;
if (lns_mapping_type_enabled(lns::mapping_type::blockchain)) expected_size += 1;
if (lns_mapping_type_enabled(lns::mapping_type::wallet)) expected_size += 1;
if (lns_mapping_type_enabled(lns::mapping_type::lokinet)) expected_size += 1;
CHECK_EQ(records.size(), expected_size);
for (lns::mapping_record const &record : records)
{
if (record.type == static_cast<uint16_t>(lns::mapping_type::messenger))
if (record.type == static_cast<uint16_t>(lns::mapping_type::session))
{
CHECK_EQ(record.name, miner_messenger_name1);
CHECK_EQ(record.name, miner_session_name1);
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.messenger_value);
CHECK_EQ(record.value, miner_key.session_value);
}
else if (record.type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
@ -1620,11 +1669,11 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.lokinet_value);
}
else if (record.type == static_cast<uint16_t>(lns::mapping_type::blockchain))
else if (record.type == static_cast<uint16_t>(lns::mapping_type::wallet))
{
CHECK_EQ(record.name, miner_wallet_name1);
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.blockchain_value);
CHECK_EQ(record.value, miner_key.wallet_value);
}
else
{
@ -1638,13 +1687,13 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
while (gen.height() <= miner_earliest_renewable_height)
gen.create_and_add_next_block();
// NOTE: Generate and add the second round of (transactions + block) to the blockchain, renew lokinet and add bob's messenger
// NOTE: Generate and add the second round of (transactions + block) to the blockchain, renew lokinet and add bob's session
uint64_t second_lns_height = 0;
{
std::string const bob_messenger_name1 = "I Like Session";
std::string const bob_session_name1 = "I Like Session";
{
std::vector<cryptonote::transaction> txs;
txs.push_back(gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, bob_messenger_name1));
txs.push_back(gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::session), bob_key.session_value, bob_session_name1));
if (lns_mapping_type_enabled(lns::mapping_type::lokinet))
{
@ -1654,8 +1703,8 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
}
second_lns_height = gen.height();
loki_register_callback(events, "check_second_lns_entries", [miner_lokinet_domain1, bob_messenger_name1, second_lns_height, miner_key, bob_key,
first_lns_height, miner_messenger_name1, miner_wallet_name1](cryptonote::core &c, size_t ev_index)
loki_register_callback(events, "check_second_lns_entries", [miner_lokinet_domain1, bob_session_name1, second_lns_height, miner_key, bob_key,
first_lns_height, miner_session_name1, miner_wallet_name1](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_second_lns_entries");
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
@ -1666,11 +1715,11 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
std::vector<lns::mapping_record> records = lns_db.get_mappings_by_user(miner_key.ed_key);
for (lns::mapping_record const &record : records)
{
if (record.type == static_cast<uint16_t>(lns::mapping_type::messenger))
if (record.type == static_cast<uint16_t>(lns::mapping_type::session))
{
CHECK_EQ(record.name, miner_messenger_name1);
CHECK_EQ(record.name, miner_session_name1);
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.messenger_value);
CHECK_EQ(record.value, miner_key.session_value);
}
else if (record.type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
@ -1678,11 +1727,11 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
CHECK_EQ(record.register_height, second_lns_height);
CHECK_EQ(record.value, miner_key.lokinet_value);
}
else if (record.type == static_cast<uint16_t>(lns::mapping_type::blockchain))
else if (record.type == static_cast<uint16_t>(lns::mapping_type::wallet))
{
CHECK_EQ(record.name, miner_wallet_name1);
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.blockchain_value);
CHECK_EQ(record.value, miner_key.wallet_value);
}
else
{
@ -1695,17 +1744,17 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
{
std::vector<lns::mapping_record> records = lns_db.get_mappings_by_user(bob_key.ed_key);
CHECK_EQ(records.size(), 1);
CHECK_EQ(records[0].name, bob_messenger_name1);
CHECK_EQ(records[0].name, bob_session_name1);
CHECK_EQ(records[0].register_height, second_lns_height);
CHECK_EQ(records[0].value, bob_key.messenger_value);
CHECK_EQ(records[0].type, static_cast<uint16_t>(lns::mapping_type::messenger));
CHECK_EQ(records[0].value, bob_key.session_value);
CHECK_EQ(records[0].type, static_cast<uint16_t>(lns::mapping_type::session));
}
return true;
});
}
loki_register_callback(events, "trigger_blockchain_detach", [miner_key, miner_messenger_name1, miner_lokinet_domain1, miner_wallet_name1, first_lns_height, second_lns_height, bob_key](cryptonote::core &c, size_t ev_index)
loki_register_callback(events, "trigger_blockchain_detach", [miner_key, miner_session_name1, miner_lokinet_domain1, miner_wallet_name1, first_lns_height, second_lns_height, bob_key](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_second_lns_entries");
cryptonote::Blockchain &blockchain = c.get_blockchain_storage();
@ -1729,17 +1778,17 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
{
std::vector<lns::mapping_record> records = lns_db.get_mappings_by_user(miner_key.ed_key);
size_t expected_size = 1;
if (lns_mapping_type_enabled(lns::mapping_type::blockchain)) expected_size += 1;
if (lns_mapping_type_enabled(lns::mapping_type::wallet)) expected_size += 1;
if (lns_mapping_type_enabled(lns::mapping_type::lokinet)) expected_size += 1;
CHECK_EQ(records.size(), expected_size);
for (lns::mapping_record const &record : records)
{
if (record.type == static_cast<uint16_t>(lns::mapping_type::messenger))
if (record.type == static_cast<uint16_t>(lns::mapping_type::session))
{
CHECK_EQ(record.name, miner_messenger_name1);
CHECK_EQ(record.name, miner_session_name1);
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.messenger_value);
CHECK_EQ(record.value, miner_key.session_value);
}
else if (record.type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
@ -1747,11 +1796,11 @@ bool loki_name_system_large_reorg::generate(std::vector<test_event_entry> &event
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.lokinet_value);
}
else if (record.type == static_cast<uint16_t>(lns::mapping_type::blockchain))
else if (record.type == static_cast<uint16_t>(lns::mapping_type::wallet))
{
CHECK_EQ(record.name, miner_wallet_name1);
CHECK_EQ(record.register_height, first_lns_height);
CHECK_EQ(record.value, miner_key.blockchain_value);
CHECK_EQ(record.value, miner_key.wallet_value);
}
else
{
@ -1803,7 +1852,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
}
lns_keys_t miner_key = make_lns_keys(miner);
char const name[] = "mydomain.loki";
std::string const name = "mydomain.loki";
cryptonote::transaction tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.lokinet_value, name);
gen.create_and_add_next_block({tx});
crypto::hash prev_txid = get_transaction_hash(tx);
@ -1823,10 +1872,10 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
CHECK_EQ(user.id, 1);
CHECK_EQ(miner_key.ed_key, user.key);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name, loki::char_count(name));
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name);
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::lokinet));
CHECK_EQ(mappings.name, std::string(name));
CHECK_EQ(mappings.name, name);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.prev_txid, crypto::null_hash);
@ -1852,10 +1901,10 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
CHECK_EQ(user.id, 1);
CHECK_EQ(miner_key.ed_key, user.key);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name, loki::char_count(name));
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), name);
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::lokinet));
CHECK_EQ(mappings.name, std::string(name));
CHECK_EQ(mappings.name, name);
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.register_height, renewal_height);
CHECK_EQ(mappings.prev_txid, prev_txid);
@ -1879,12 +1928,13 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
auto make_lns_tx_with_custom_extra = [&](loki_chain_generator &gen,
std::vector<test_event_entry> &events,
cryptonote::account_base const &src,
cryptonote::tx_extra_loki_name_system &data) -> void {
cryptonote::tx_extra_loki_name_system const &data) -> void {
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
uint64_t burn_requirement = lns::burn_requirement_in_atomic_loki(new_hf_version);
lns::burn_type burn_type = lns::mapping_type_to_burn_type(static_cast<lns::mapping_type>(data.type));
uint64_t burn_requirement = lns::burn_requirement_in_atomic_loki(new_hf_version, burn_type);
std::vector<uint8_t> extra;
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
cryptonote::add_burned_amount_to_tx_extra(extra, burn_requirement);
@ -1904,11 +1954,11 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
data.owner = miner_key.ed_key;
// Blockchain
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
if (lns_mapping_type_enabled(lns::mapping_type::wallet))
{
data.type = static_cast<uint16_t>(lns::mapping_type::blockchain);
data.name = std::string(lns::BLOCKCHAIN_NAME_MAX, 'A');
data.value = miner_key.blockchain_value;
data.type = static_cast<uint16_t>(lns::mapping_type::wallet);
data.name = std::string(lns::WALLET_NAME_MAX, 'A');
data.value = miner_key.wallet_value;
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
@ -1921,11 +1971,11 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
// Messenger
// Session
{
data.type = static_cast<uint16_t>(lns::mapping_type::messenger);
data.name = std::string(lns::MESSENGER_DISPLAY_NAME_MAX, 'A');
data.value = std::string(lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH, 'a');
data.type = static_cast<uint16_t>(lns::mapping_type::session);
data.name = std::string(lns::SESSION_DISPLAY_NAME_MAX, 'A');
data.value = std::string(lns::SESSION_PUBLIC_KEY_BINARY_LENGTH, 'a');
data.value[0] = '0';
data.value[1] = '5';
make_lns_tx_with_custom_extra(gen, events, miner, data);
@ -1956,7 +2006,7 @@ bool loki_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
}
lns_keys_t lns_keys = make_lns_keys(miner);
lns::mapping_type const types[] = {lns::mapping_type::messenger, lns::mapping_type::blockchain, lns::mapping_type::lokinet};
lns::mapping_type const types[] = {lns::mapping_type::session, lns::mapping_type::wallet, lns::mapping_type::lokinet};
for (int i = 0; i < 2; i++)
{
bool under_burn = (i == 0);
@ -1967,14 +2017,14 @@ bool loki_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
std::string value;
std::string name;
if (type == lns::mapping_type::messenger)
if (type == lns::mapping_type::session)
{
value = lns_keys.messenger_value;
name = "My Friendly Messenger Name";
value = lns_keys.session_value;
name = "My Friendly Session Name";
}
else if (type == lns::mapping_type::blockchain)
else if (type == lns::mapping_type::wallet)
{
value = lns_keys.blockchain_value;
value = lns_keys.wallet_value;
name = "My Friendly Wallet Name";
}
else if (type == lns::mapping_type::lokinet)
@ -1985,9 +2035,10 @@ bool loki_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
else
assert("Unhandled type enum" == nullptr);
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
uint64_t burn = lns::burn_requirement_in_atomic_loki(new_hf_version);
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
lns::burn_type burn_type = lns::mapping_type_to_burn_type(type);
uint64_t burn = lns::burn_requirement_in_atomic_loki(new_hf_version, burn_type);
if (under_burn) burn -= 1;
else burn += 1;
@ -2013,13 +2064,13 @@ bool loki_name_system_wrong_version::generate(std::vector<test_event_entry> &eve
cryptonote::tx_extra_loki_name_system data = {};
data.version = 0xFF;
data.owner = miner_key.ed_key;
data.type = static_cast<uint16_t>(lns::mapping_type::messenger);
data.value = miner_key.messenger_value;
data.type = static_cast<uint16_t>(lns::mapping_type::session);
data.value = miner_key.session_value;
data.name = "my_lns_name";
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
uint64_t burn_requirement = lns::burn_requirement_in_atomic_loki(new_hf_version);
uint64_t burn_requirement = lns::burn_requirement_in_atomic_loki(new_hf_version, lns::burn_type::session);
std::vector<uint8_t> extra;
cryptonote::add_loki_name_system_to_tx_extra(extra, data);

View File

@ -54,6 +54,7 @@ struct loki_core_test_state_change_ip_penalty_disallow_dupes
struct loki_name_system_disallow_reserved_type : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_expiration : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_get_mappings_by_user : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_get_mapping_by_name_and_type : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_handles_duplicate_in_lns_db : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_handles_duplicate_in_tx_pool : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_invalid_tx_extra_params : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };

View File

@ -86,7 +86,15 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
try
{
std::vector<tools::wallet2::pending_tx> ptx;
ptx = w1.create_transactions_2(dsts, mix_in_factor, 0, 0, std::vector<uint8_t>(), 0, {}, {});
cryptonote::loki_construct_tx_params tx_params;
ptx = w1.create_transactions_2(dsts,
mix_in_factor,
0 /*unlock_time*/,
0 /*priority*/,
std::vector<uint8_t>() /*extra_base*/,
0 /*subaddr_account*/,
{} /*subaddr_indices*/,
tx_params);
for (auto &p: ptx)
w1.commit_tx(p);
return true;

View File

@ -12,53 +12,53 @@ TEST(loki_name_system, lokinet_domain_names)
// Should work
{
char const name[] = "mydomain.loki";
ASSERT_TRUE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "mydomain.loki";
ASSERT_TRUE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "a.loki";
ASSERT_TRUE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "a.loki";
ASSERT_TRUE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "xn--bcher-kva.loki";
ASSERT_TRUE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "xn--bcher-kva.loki";
ASSERT_TRUE(lns::validate_lns_name(lokinet, name));
}
// Should fail
{
char const name[] = "";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "mydomain.loki.example";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "mydomain.loki.example";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "mydomain.loki.com";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "mydomain.loki.com";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "mydomain.com";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "mydomain.com";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "mydomain";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "mydomain";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "xn--bcher-kva.lok";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "xn--bcher-kva.lok";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
{
char const name[] = "a_b_c.loki";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
std::string const name = "a_b_c.loki";
ASSERT_FALSE(lns::validate_lns_name(lokinet, name));
}
}