mirror of https://github.com/oxen-io/oxen-core.git
Send LNS values as blobs to the blockchain
This commit is contained in:
parent
cb955c1952
commit
1093bab034
|
@ -387,7 +387,7 @@ namespace cryptonote
|
|||
crypto::ed25519_public_key owner;
|
||||
uint16_t type;
|
||||
std::string name;
|
||||
std::string value;
|
||||
std::string value; // binary format of the name->value mapping
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(owner);
|
||||
|
|
|
@ -3440,7 +3440,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
|||
{
|
||||
cryptonote::tx_extra_loki_name_system data;
|
||||
std::string fail_reason;
|
||||
if (!lns::validate_lns_tx(hf_version, nettype(), tx, &data, nullptr /*lns_value*/, &fail_reason))
|
||||
if (!lns::validate_lns_tx(hf_version, nettype(), tx, &data, &fail_reason))
|
||||
{
|
||||
MERROR_VER("TX type=" << tx.type << ", hash=" << get_transaction_hash(tx) << ", owner=" << data.owner << ", type=" << (int)data.type << ", name=" << data.name << ", reason=" << fail_reason);
|
||||
return false;
|
||||
|
|
|
@ -232,225 +232,269 @@ static bool char_is_alphanum(char c)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool validate_lns_name_and_value(cryptonote::network_type nettype, uint16_t type, char const *name, int name_len, char const *value, int value_len, lns_value *blob, std::string *reason)
|
||||
bool validate_lns_name(uint16_t type, char const *name, int name_len, std::string *reason)
|
||||
{
|
||||
if (blob) *blob = {};
|
||||
std::stringstream err_stream;
|
||||
LOKI_DEFER { if (reason) *reason = std::move(err_stream.str()); };
|
||||
LOKI_DEFER { if (reason) *reason = err_stream.str(); };
|
||||
|
||||
// NOTE: Validate value length, and convert the value into a blob if blob is given
|
||||
int max_name_len = lns::GENERIC_NAME_MAX;
|
||||
{
|
||||
cryptonote::address_parse_info addr_info = {};
|
||||
if (type == static_cast<uint16_t>(mapping_type::blockchain))
|
||||
{
|
||||
max_name_len = BLOCKCHAIN_NAME_MAX;
|
||||
if (value_len == 0 || !get_account_address_from_str(addr_info, nettype, std::string(value, value_len)))
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
if (value_len == 0)
|
||||
{
|
||||
err_stream << "The name=";
|
||||
err_stream.write(name, name_len);
|
||||
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);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int max_value_len = lns::GENERIC_VALUE_MAX;
|
||||
bool value_require_exact_len = true;
|
||||
if (type == static_cast<uint16_t>(mapping_type::lokinet))
|
||||
{
|
||||
max_name_len = LOKINET_DOMAIN_NAME_MAX;
|
||||
max_value_len = (LOKINET_ADDRESS_BINARY_LENGTH * 2);
|
||||
}
|
||||
else if (type == static_cast<uint16_t>(mapping_type::messenger))
|
||||
{
|
||||
max_name_len = MESSENGER_DISPLAY_NAME_MAX;
|
||||
max_value_len = (MESSENGER_PUBLIC_KEY_BINARY_LENGTH * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
value_require_exact_len = false;
|
||||
}
|
||||
|
||||
if (value_require_exact_len)
|
||||
{
|
||||
if (value_len != max_value_len)
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the value's length=" << value_len << ", does not equal the required length=" << max_value_len << ", given value=";
|
||||
err_stream.write(value, value_len);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value_len > max_value_len || value_len == 0)
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the value's length=" << value_len << " is 0 or exceeds the maximum length=" << max_value_len << ", given value=";
|
||||
err_stream.write(value, value_len);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == static_cast<uint16_t>(mapping_type::blockchain))
|
||||
{
|
||||
if (blob)
|
||||
{
|
||||
blob->len = sizeof(addr_info.address);
|
||||
memcpy(blob->buffer.data(), &addr_info.address, blob->len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: Check value is hex
|
||||
if ((value_len % 2) != 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int val_index = 0; val_index < value_len; 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 (blob) // NOTE: Given blob, write the binary output
|
||||
blob->buffer.data()[blob->len++] = loki::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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
// NOTE: Validate name length
|
||||
if (name_len > max_name_len || name_len == 0)
|
||||
{
|
||||
if (name_len > max_name_len || name_len == 0)
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Validate domain specific requirements
|
||||
if (type == static_cast<uint16_t>(mapping_type::messenger))
|
||||
{
|
||||
}
|
||||
else if (type == static_cast<uint16_t>(mapping_type::lokinet))
|
||||
{
|
||||
// Domain has to start with a letter or digit, and can have letters, digits, or hyphens in between and must end with a .loki
|
||||
// ^[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 (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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!char_is_alphanum(name[0])) // Must start with alphanumeric
|
||||
{
|
||||
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 << "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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == static_cast<uint16_t>(mapping_type::messenger))
|
||||
char const SUFFIX[] = ".loki";
|
||||
char const *name_suffix = name + (name_len - loki::char_count(SUFFIX));
|
||||
if (memcmp(name_suffix, SUFFIX, loki::char_count(SUFFIX)) != 0) // Must end with .loki
|
||||
{
|
||||
// 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'))
|
||||
if (reason)
|
||||
{
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (type == static_cast<uint16_t>(mapping_type::lokinet))
|
||||
|
||||
char const *char_preceeding_suffix = name_suffix - 1;
|
||||
if (!char_is_alphanum(char_preceeding_suffix[0])) // Characted preceeding suffix must be alphanumeric
|
||||
{
|
||||
// Domain has to start with a letter or digit, and can have letters, digits, or hyphens in between and must end with a .loki
|
||||
// ^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.loki$
|
||||
if (reason)
|
||||
{
|
||||
char const SHORTEST_DOMAIN[] = "a.loki";
|
||||
if (name_len < 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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!char_is_alphanum(name[0])) // Must start with alphanumeric
|
||||
char const *begin = name + 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
|
||||
{
|
||||
char c = it[0];
|
||||
if (!(char_is_alphanum(c) || c == '-'))
|
||||
{
|
||||
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 << "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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char const SUFFIX[] = ".loki";
|
||||
char const *name_suffix = name + (name_len - 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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char const *char_preceeding_suffix = name_suffix - 1;
|
||||
if (!char_is_alphanum(char_preceeding_suffix[0])) // Characted preceeding suffix must be alphanumeric
|
||||
{
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char const *begin = name + 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
|
||||
{
|
||||
char c = it[0];
|
||||
if (!(char_is_alphanum(c) || c == '-'))
|
||||
{
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_lns_tx(uint8_t hf_version, cryptonote::network_type nettype, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system *entry, lns_value *blob, std::string *reason)
|
||||
static bool check_lengths(uint16_t type, char const *value, int len, int max, bool require_exact_len, std::string *reason)
|
||||
{
|
||||
bool result = true;
|
||||
if (require_exact_len)
|
||||
{
|
||||
if (len != max)
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len > max || len == 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
std::stringstream err_stream;
|
||||
err_stream << "LNS type=" << type << ", specifies mapping from name -> value where the value's length=" << len;
|
||||
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);
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (blob) *blob = {};
|
||||
std::stringstream err_stream;
|
||||
|
||||
cryptonote::address_parse_info addr_info = {};
|
||||
if (type == static_cast<uint16_t>(mapping_type::blockchain))
|
||||
{
|
||||
if (value_len == 0 || !get_account_address_from_str(addr_info, nettype, std::string(value, value_len)))
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
if (value_len == 0)
|
||||
{
|
||||
err_stream << "The value=";
|
||||
err_stream.write(value, value_len);
|
||||
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);
|
||||
}
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 value_require_exact_len = false;
|
||||
|
||||
if (!check_lengths(type, value, value_len, max_value_len, value_require_exact_len, reason))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == static_cast<uint16_t>(mapping_type::blockchain))
|
||||
{
|
||||
if (blob)
|
||||
{
|
||||
blob->len = sizeof(addr_info.address);
|
||||
memcpy(blob->buffer.data(), &addr_info.address, blob->len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: Check value is hex
|
||||
if ((value_len % 2) != 0)
|
||||
{
|
||||
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;
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int val_index = 0; val_index < value_len; 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 (blob) // NOTE: Given blob, write the binary output
|
||||
blob->buffer.data()[blob->len++] = loki::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);
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == static_cast<uint16_t>(mapping_type::messenger))
|
||||
{
|
||||
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 (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);
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_lns_value_binary(uint16_t type, char const *value, int value_len, 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);
|
||||
else value_require_exact_len = false;
|
||||
|
||||
if (!check_lengths(type, value, value_len, max_value_len, value_require_exact_len, reason))
|
||||
return false;
|
||||
|
||||
if (type == static_cast<uint16_t>(lns::mapping_type::blockchain))
|
||||
{
|
||||
// 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));
|
||||
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);
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_lns_tx(uint8_t hf_version, cryptonote::network_type nettype, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system *entry, std::string *reason)
|
||||
{
|
||||
cryptonote::tx_extra_loki_name_system entry_;
|
||||
if (!entry) entry = &entry_;
|
||||
|
@ -458,27 +502,39 @@ bool validate_lns_tx(uint8_t hf_version, cryptonote::network_type nettype, crypt
|
|||
|
||||
if (!cryptonote::get_loki_name_system_from_tx_extra(tx.extra, *entry))
|
||||
{
|
||||
err_stream << "TX: " << tx.type << " " << get_transaction_hash(tx) << ", didn't have loki name service in the tx_extra";
|
||||
if (reason) *reason = std::move(err_stream.str());
|
||||
if (reason)
|
||||
{
|
||||
err_stream << "TX: " << tx.type << " " << get_transaction_hash(tx) << ", didn't have loki name service in the tx_extra";
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry->type >= static_cast<uint16_t>(lns::mapping_type::start_reserved) && entry->type <= static_cast<uint16_t>(mapping_type::end_reserved))
|
||||
{
|
||||
err_stream << "TX: " << tx.type << " " << get_transaction_hash(tx) << " specifying type = " << static_cast<uint16_t>(entry->type) << " that is unused, but reserved by the protocol";
|
||||
if (reason) *reason = std::move(err_stream.str());
|
||||
if (reason)
|
||||
{
|
||||
err_stream << "TX: " << tx.type << " " << get_transaction_hash(tx) << " specifying type = " << static_cast<uint16_t>(entry->type) << " that is unused, but reserved by the protocol";
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t burn = cryptonote::get_burned_amount_from_tx_extra(tx.extra);
|
||||
if (!validate_lns_name_and_value(nettype, entry->type, entry->name.data(), static_cast<int>(entry->name.size()), entry->value.data(), static_cast<int>(entry->value.size()), blob, reason))
|
||||
if (!validate_lns_name(entry->type, entry->name.data(), static_cast<int>(entry->name.size()), reason))
|
||||
return false;
|
||||
|
||||
if (!validate_lns_value_binary(entry->type, entry->value.data(), static_cast<int>(entry->value.size()), reason))
|
||||
return false;
|
||||
|
||||
uint64_t const burn_required = burn_requirement_in_atomic_loki(hf_version);
|
||||
if (burn != burn_required)
|
||||
{
|
||||
err_stream << "LNS TX=" << cryptonote::get_transaction_hash(tx) << ", burned insufficient amounts of loki=" << burn << ", require=" << burn_required;
|
||||
if (reason) *reason = std::move(err_stream.str());
|
||||
if (reason)
|
||||
{
|
||||
err_stream << "LNS TX=" << cryptonote::get_transaction_hash(tx) << ", burned insufficient amounts of loki=" << burn << ", require=" << burn_required;
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -675,10 +731,9 @@ bool name_system_db::add_block(const cryptonote::block &block, const std::vector
|
|||
if (tx.type != cryptonote::txtype::loki_name_system)
|
||||
continue;
|
||||
|
||||
lns_value entry_value = {};
|
||||
cryptonote::tx_extra_loki_name_system entry = {};
|
||||
std::string fail_reason;
|
||||
if (!validate_lns_tx(block.major_version, nettype, tx, &entry, &entry_value, &fail_reason))
|
||||
if (!validate_lns_tx(block.major_version, nettype, tx, &entry, &fail_reason))
|
||||
{
|
||||
LOG_PRINT_L1("LNS TX: Failed to validate for tx=" << get_transaction_hash(tx) << ". This should have failed validation earlier reason=" << fail_reason);
|
||||
assert("Failed to validate acquire name service. Should already have failed validation prior" == nullptr);
|
||||
|
@ -701,7 +756,7 @@ bool name_system_db::add_block(const cryptonote::block &block, const std::vector
|
|||
}
|
||||
assert(user_id != 0);
|
||||
|
||||
if (!save_mapping(static_cast<uint16_t>(entry.type), entry.name, entry_value, height, user_id))
|
||||
if (!save_mapping(static_cast<uint16_t>(entry.type), entry.name, entry.value, height, user_id))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to save LNS entry to DB tx: " << cryptonote::get_transaction_hash(tx)
|
||||
<< ", type: " << (uint16_t)entry.type
|
||||
|
@ -742,12 +797,12 @@ bool name_system_db::save_user(crypto::ed25519_public_key const &key, int64_t *r
|
|||
return result;
|
||||
}
|
||||
|
||||
bool name_system_db::save_mapping(uint16_t type, std::string const &name, lns_value const &value, uint64_t height, int64_t user_id)
|
||||
bool name_system_db::save_mapping(uint16_t type, std::string const &name, std::string const &value, uint64_t height, int64_t user_id)
|
||||
{
|
||||
sqlite3_stmt *statement = save_mapping_sql;
|
||||
sqlite3_bind_int (statement, mapping_record_row_type, type);
|
||||
sqlite3_bind_text (statement, mapping_record_row_name, name.data(), name.size(), nullptr /*destructor*/);
|
||||
sqlite3_bind_blob (statement, mapping_record_row_value, value.buffer.data(), value.len, nullptr /*destructor*/);
|
||||
sqlite3_bind_blob (statement, mapping_record_row_value, value.data(), value.size(), nullptr /*destructor*/);
|
||||
sqlite3_bind_int64(statement, mapping_record_row_register_height, static_cast<int64_t>(height));
|
||||
sqlite3_bind_int64(statement, mapping_record_row_user_id, user_id);
|
||||
bool result = sql_run_statement(nettype, lns_sql_type::save_mapping, statement, nullptr);
|
||||
|
|
|
@ -37,9 +37,15 @@ struct lns_value
|
|||
uint64_t burn_requirement_in_atomic_loki(uint8_t hf_version);
|
||||
sqlite3 *init_loki_name_system(char const *file_path);
|
||||
uint64_t lokinet_expiry_blocks(cryptonote::network_type nettype, uint64_t *renew_window);
|
||||
bool validate_lns_name_and_value(cryptonote::network_type nettype, uint16_t type, char const *name, int name_len, char const *value, int value_len, lns_value *blob = nullptr, std::string *reason = nullptr);
|
||||
bool validate_lns_tx(uint8_t hf_version, cryptonote::network_type nettype, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system *entry = nullptr, lns_value *blob = nullptr, std::string *reason = nullptr);
|
||||
bool validate_lns_name(uint16_t type, char const *name, int name_len, 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_tx(uint8_t hf_version, cryptonote::network_type nettype, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system *entry = nullptr, std::string *reason = nullptr);
|
||||
bool validate_mapping_type(std::string const &type, uint16_t *mapping_type, std::string *reason);
|
||||
lns_value convert_value_to_lns_binary_value(uint16_t type, std::string const &value);
|
||||
|
||||
struct user_record
|
||||
{
|
||||
|
@ -88,7 +94,7 @@ struct name_system_db
|
|||
uint64_t height () { return last_processed_height; }
|
||||
|
||||
bool save_user (crypto::ed25519_public_key const &key, int64_t *row_id);
|
||||
bool save_mapping (uint16_t type, std::string const &name, lns_value const &value, uint64_t height, int64_t user_id);
|
||||
bool save_mapping (uint16_t type, std::string const &name, std::string const &value, uint64_t height, int64_t user_id);
|
||||
bool save_settings (uint64_t top_height, crypto::hash const &top_hash, int version);
|
||||
|
||||
bool expire_mappings(uint64_t height);
|
||||
|
|
|
@ -8552,7 +8552,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_and_value(nettype(), type, name.data(), name.size(), value.data(), value.size(), nullptr /*lns_value*/, reason))
|
||||
if (!lns::validate_lns_name(type, name.data(), name.size(), reason))
|
||||
return {};
|
||||
|
||||
lns::lns_value value_blob;
|
||||
if (!lns::validate_lns_value(nettype(), type, value.data(), value.size(), &value_blob, reason))
|
||||
return {};
|
||||
|
||||
if (priority == tools::tx_priority_blink)
|
||||
|
@ -8580,7 +8584,8 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
|
|||
entry.owner = pkey;
|
||||
entry.type = type;
|
||||
entry.name = name;
|
||||
entry.value = value;
|
||||
entry.value.resize(value_blob.len);
|
||||
memcpy(&entry.value[0], value_blob.buffer.data(), value_blob.len);
|
||||
|
||||
std::vector<uint8_t> extra;
|
||||
add_loki_name_system_to_tx_extra(extra, entry);
|
||||
|
|
|
@ -1439,6 +1439,7 @@ struct loki_chain_generator
|
|||
cryptonote::transaction create_state_change_tx(service_nodes::new_state state, const crypto::public_key& pub_key, uint64_t height = -1, const std::vector<uint64_t>& voters = {}, uint64_t fee = 0) const;
|
||||
cryptonote::checkpoint_t create_service_node_checkpoint(uint64_t block_height, size_t num_votes) const;
|
||||
|
||||
// value: Takes the binary value NOT the human readable version, of the name->value mapping
|
||||
static const uint64_t LNS_AUTO_BURN = static_cast<uint64_t>(-1);
|
||||
cryptonote::transaction create_loki_name_system_tx (cryptonote::account_base const &src, uint16_t type, std::string const &value, std::string const &name, crypto::ed25519_public_key const *owner = nullptr, uint64_t burn = LNS_AUTO_BURN) const;
|
||||
|
||||
|
|
|
@ -1014,6 +1014,39 @@ static bool lns_mapping_type_enabled(lns::mapping_type type)
|
|||
return result;
|
||||
}
|
||||
|
||||
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 lokinet_value;
|
||||
std::string messenger_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 lokinet_value_hex;
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
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.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.lokinet_value_hex = epee::string_tools::pod_to_hex(result.ed_key);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
|
||||
|
@ -1044,15 +1077,11 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
|
|||
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
|
||||
}
|
||||
|
||||
crypto::ed25519_public_key miner_key;
|
||||
crypto::ed25519_secret_key miner_skey;
|
||||
crypto_sign_ed25519_seed_keypair(miner_key.data, miner_skey.data, reinterpret_cast<const unsigned char *>(miner.get_keys().m_spend_secret_key.data));
|
||||
|
||||
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 miner_key_str = epee::string_tools::pod_to_hex(miner_key);
|
||||
cryptonote::transaction tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key_str, name);
|
||||
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});
|
||||
|
||||
uint64_t height_of_lns_entry = gen.height();
|
||||
|
@ -1070,16 +1099,16 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
|
|||
DEFINE_TESTS_ERROR_CONTEXT("check_lns_entries");
|
||||
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
|
||||
|
||||
lns::user_record user = lns_db.get_user_by_key(miner_key);
|
||||
lns::user_record user = lns_db.get_user_by_key(miner_key.ed_key);
|
||||
CHECK_EQ(user.loaded, true);
|
||||
CHECK_EQ(user.id, 1);
|
||||
CHECK_EQ(miner_key, user.key);
|
||||
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));
|
||||
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.value, std::string((char *)miner_key.data, sizeof(miner_key)));
|
||||
CHECK_EQ(mappings.value, miner_key.lokinet_value);
|
||||
CHECK_EQ(mappings.register_height, height_of_lns_entry);
|
||||
CHECK_EQ(mappings.user_id, user.id);
|
||||
return true;
|
||||
|
@ -1102,10 +1131,10 @@ bool loki_name_system_expiration::generate(std::vector<test_event_entry> &events
|
|||
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
|
||||
|
||||
// TODO(loki): We should probably expire users that no longer have any mappings remaining
|
||||
lns::user_record user = lns_db.get_user_by_key(miner_key);
|
||||
lns::user_record user = lns_db.get_user_by_key(miner_key.ed_key);
|
||||
CHECK_EQ(user.loaded, true);
|
||||
CHECK_EQ(user.id, 1);
|
||||
CHECK_EQ(miner_key, user.key);
|
||||
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));
|
||||
CHECK_EQ(mappings.loaded, false);
|
||||
|
@ -1155,21 +1184,12 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
|
||||
}
|
||||
|
||||
crypto::ed25519_public_key bob_key;
|
||||
crypto::ed25519_secret_key bob_skey;
|
||||
crypto_sign_ed25519_seed_keypair(bob_key.data, bob_skey.data, reinterpret_cast<const unsigned char *>(bob.get_keys().m_spend_secret_key.data));
|
||||
|
||||
// NOTE: Register some messenger names
|
||||
char messenger_key[lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH] = {};
|
||||
messenger_key[0] = 5;
|
||||
memcpy(messenger_key + 1, &bob_key, sizeof(bob_key));
|
||||
|
||||
lns_keys_t bob_key = make_lns_keys(bob);
|
||||
std::string messenger_name1 = "MyName";
|
||||
std::string messenger_name2 = "AnotherName";
|
||||
{
|
||||
std::string messenger_key_hex = epee::string_tools::pod_to_hex(messenger_key);
|
||||
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), messenger_key_hex, messenger_name1);
|
||||
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::messenger), messenger_key_hex, messenger_name2, &bob_key);
|
||||
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);
|
||||
gen.create_and_add_next_block({tx1, tx2});
|
||||
}
|
||||
uint64_t messenger_height = gen.height();
|
||||
|
@ -1178,7 +1198,7 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
{
|
||||
DEFINE_TESTS_ERROR_CONTEXT("check_lns_entries_before_checkpoint");
|
||||
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(bob_key);
|
||||
std::vector<lns::mapping_record> records = lns_db.get_mappings_by_user(bob_key.ed_key);
|
||||
CHECK_EQ(records.empty(), true);
|
||||
return true;
|
||||
});
|
||||
|
@ -1189,9 +1209,8 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
if (lns_mapping_type_enabled(lns::mapping_type::lokinet))
|
||||
{
|
||||
{
|
||||
std::string bob_key_str = epee::string_tools::pod_to_hex(bob_key);
|
||||
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::lokinet), bob_key_str, lokinet_name1);
|
||||
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), bob_key_str, lokinet_name2, &bob_key);
|
||||
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::lokinet), bob_key.lokinet_value, lokinet_name1);
|
||||
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), bob_key.lokinet_value, lokinet_name2, &bob_key.ed_key);
|
||||
gen.create_and_add_next_block({tx1, tx2});
|
||||
}
|
||||
}
|
||||
|
@ -1204,8 +1223,8 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
{
|
||||
{
|
||||
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_addr, wallet_name1);
|
||||
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::blockchain), bob_addr, wallet_name2, &bob_key);
|
||||
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);
|
||||
gen.create_and_add_next_block({tx1, tx2});
|
||||
}
|
||||
}
|
||||
|
@ -1218,19 +1237,15 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
|
||||
gen.create_and_add_next_block();
|
||||
|
||||
loki_register_callback(events, "check_lns_entries", [&events, bob, bob_key, messenger_key,
|
||||
loki_register_callback(events, "check_lns_entries", [&events, bob_key,
|
||||
wallet_height, wallet_name1, wallet_name2,
|
||||
messenger_height, messenger_name1, messenger_name2,
|
||||
lokinet_height, lokinet_name1, lokinet_name2
|
||||
](cryptonote::core &c, size_t ev_index)
|
||||
{
|
||||
crypto::ed25519_public_key bob_pkey;
|
||||
crypto::ed25519_secret_key bob_skey;
|
||||
crypto_sign_ed25519_seed_keypair(bob_pkey.data, bob_skey.data, reinterpret_cast<const unsigned char *>(bob.get_keys().m_spend_secret_key.data));
|
||||
|
||||
DEFINE_TESTS_ERROR_CONTEXT("check_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(bob_pkey);
|
||||
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;
|
||||
|
@ -1238,18 +1253,14 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
if (lns_mapping_type_enabled(lns::mapping_type::lokinet)) expected_size += 2;
|
||||
CHECK_EQ(records.size(), expected_size);
|
||||
|
||||
auto messenger_value_hex_str = std::string(messenger_key, sizeof(messenger_key));
|
||||
auto lokinet_value_hex_str = std::string((char *)bob_key.data, sizeof(bob_key));
|
||||
auto wallet_value_str = std::string((char *)&bob.get_keys().m_account_address, sizeof(bob.get_keys().m_account_address));
|
||||
|
||||
if (lns_mapping_type_enabled(lns::mapping_type::messenger))
|
||||
{
|
||||
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, messenger_value_hex_str);
|
||||
CHECK_EQ(records[1].value, messenger_value_hex_str);
|
||||
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));
|
||||
}
|
||||
|
@ -1260,8 +1271,8 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
CHECK_EQ(records[3].name, lokinet_name2);
|
||||
CHECK_EQ(records[2].register_height, lokinet_height);
|
||||
CHECK_EQ(records[3].register_height, lokinet_height);
|
||||
CHECK_EQ(records[2].value, lokinet_value_hex_str);
|
||||
CHECK_EQ(records[3].value, lokinet_value_hex_str);
|
||||
CHECK_EQ(records[2].value, bob_key.lokinet_value);
|
||||
CHECK_EQ(records[3].value, bob_key.lokinet_value);
|
||||
CHECK_EQ(records[2].type, static_cast<uint16_t>(lns::mapping_type::lokinet));
|
||||
CHECK_EQ(records[3].type, static_cast<uint16_t>(lns::mapping_type::lokinet));
|
||||
}
|
||||
|
@ -1272,8 +1283,8 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
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, wallet_value_str);
|
||||
CHECK_EQ(records[5].value, wallet_value_str);
|
||||
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));
|
||||
}
|
||||
|
@ -1283,38 +1294,6 @@ bool loki_name_system_get_mappings_by_user::generate(std::vector<test_event_entr
|
|||
return true;
|
||||
}
|
||||
|
||||
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 lokinet_value;
|
||||
std::string messenger_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 lokinet_value_hex;
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
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.lokinet_value = std::string((char *)result.ed_key.data, sizeof(result.ed_key));
|
||||
|
||||
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.lokinet_value_hex = epee::string_tools::pod_to_hex(result.ed_key);
|
||||
return result;
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -1357,12 +1336,12 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
|
|||
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_hex, messenger_name);
|
||||
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.messenger_value_hex, messenger_name);
|
||||
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);
|
||||
|
||||
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_hex, 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, messenger_name);
|
||||
gen.create_and_add_next_block({bar, bar2, bar3});
|
||||
}
|
||||
else
|
||||
|
@ -1381,7 +1360,7 @@ bool loki_name_system_handles_duplicate_in_lns_db::generate(std::vector<test_eve
|
|||
gen.create_and_add_next_block(); // 2 checkpoints, commit LNS from all new blocks now checkpointed to db
|
||||
|
||||
{
|
||||
cryptonote::transaction bar6 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value_hex, messenger_name);
|
||||
cryptonote::transaction bar6 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
|
||||
gen.add_tx(bar6, false /*can_be_added_to_blockchain*/, "Duplicate name requested by new owner: original already exists in lns db");
|
||||
}
|
||||
|
||||
|
@ -1471,12 +1450,12 @@ bool loki_name_system_handles_duplicate_in_staging_area::generate(std::vector<te
|
|||
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_hex, messenger_name);
|
||||
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.messenger_value_hex, messenger_name);
|
||||
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);
|
||||
|
||||
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_hex, 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, messenger_name);
|
||||
gen.create_and_add_next_block({bar, bar2, bar3});
|
||||
}
|
||||
else
|
||||
|
@ -1485,7 +1464,7 @@ bool loki_name_system_handles_duplicate_in_staging_area::generate(std::vector<te
|
|||
}
|
||||
|
||||
// NOTE: Make duplicate, but not checkpointed yet, so in the staging area should be rejected
|
||||
cryptonote::transaction bar5 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value_hex, messenger_name);
|
||||
cryptonote::transaction bar5 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
|
||||
gen.add_tx(bar5, false /*can_be_added_to_blockchain*/, "Duplicate name requested by new owner: original already exists in staging area");
|
||||
}
|
||||
uint64_t height_of_lns_entry = gen.height();
|
||||
|
@ -1584,16 +1563,16 @@ bool loki_name_system_handles_duplicate_in_tx_pool::generate(std::vector<test_ev
|
|||
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_hex, messenger_name);
|
||||
cryptonote::transaction bar2 = gen.create_and_add_loki_name_system_tx(miner, custom_type, bob_key.messenger_value_hex, messenger_name);
|
||||
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);
|
||||
|
||||
// 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_hex, messenger_name);
|
||||
cryptonote::transaction bar4 = gen.create_loki_name_system_tx(bob, static_cast<uint16_t>(lns::mapping_type::messenger), bob_key.messenger_value, messenger_name);
|
||||
gen.add_tx(bar4, false /*can_be_added_to_blockchain*/, "Duplicate name requested by new owner: original already exists in tx pool");
|
||||
|
||||
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_hex, 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, messenger_name);
|
||||
gen.create_and_add_next_block({bar, bar2, bar3});
|
||||
}
|
||||
else
|
||||
|
@ -1665,10 +1644,7 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
|
|||
gen.add_n_blocks(30); /// generate some outputs and unlock them
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
crypto::ed25519_public_key miner_key;
|
||||
crypto::ed25519_secret_key miner_skey;
|
||||
crypto_sign_ed25519_seed_keypair(miner_key.data, miner_skey.data, reinterpret_cast<const unsigned char *>(miner.get_keys().m_spend_secret_key.data));
|
||||
|
||||
lns_keys_t miner_key = make_lns_keys(miner);
|
||||
// Manually construct transaction with invalid tx extra
|
||||
{
|
||||
auto make_lns_tx_with_custom_extra = [&](loki_chain_generator &gen,
|
||||
|
@ -1696,9 +1672,9 @@ 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;
|
||||
valid_data.owner = miner_key.ed_key;
|
||||
valid_data.type = static_cast<uint16_t>(lns::mapping_type::blockchain);
|
||||
valid_data.value = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false, miner.get_keys().m_account_address);
|
||||
valid_data.value = miner_key.blockchain_value;
|
||||
valid_data.name = "my_lns_name";
|
||||
|
||||
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
|
||||
|
@ -1770,21 +1746,17 @@ bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
|
|||
valid_data.type = static_cast<uint16_t>(lns::mapping_type::messenger);
|
||||
{
|
||||
cryptonote::tx_extra_loki_name_system data = valid_data;
|
||||
data.value = std::string(reinterpret_cast<char const *>(miner_key.data), sizeof(miner_key));
|
||||
stream << "(Messenger) Key invalid, not prefixed with 0x05: " << data.value;
|
||||
data.value[0] = 'a';
|
||||
stream << "(Messenger) 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
|
||||
char messenger_key[lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH] = {};
|
||||
messenger_key[0] = 5;
|
||||
memcpy(messenger_key + 1, miner_key.data, sizeof(miner_key));
|
||||
std::string messenger_key_hex = epee::string_tools::pod_to_hex(messenger_key);
|
||||
valid_data.value = messenger_key_hex;
|
||||
valid_data.value = miner_key.messenger_value;
|
||||
{
|
||||
cryptonote::tx_extra_loki_name_system data = valid_data;
|
||||
stream << "(Messenger) Key should be valid, prefixed with 0x05: " << data.value;
|
||||
stream << "(Messenger) Key should be valid, prefixed with 0x05: " << miner_key.messenger_value_hex;
|
||||
make_lns_tx_with_custom_extra(gen, events, miner, data, true, stream.str().c_str());
|
||||
stream.clear();
|
||||
}
|
||||
|
@ -1889,7 +1861,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";
|
||||
cryptonote::transaction tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.lokinet_value_hex, name);
|
||||
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});
|
||||
|
||||
uint64_t height_of_lns_entry = gen.height();
|
||||
|
@ -1928,7 +1900,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
|
|||
gen.create_and_add_next_block();
|
||||
|
||||
// In the renewal window, try and renew the lokinet entry
|
||||
cryptonote::transaction renew_tx = gen.create_and_add_loki_name_system_tx(miner, static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.lokinet_value_hex, name);
|
||||
cryptonote::transaction renew_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({renew_tx});
|
||||
uint64_t renewal_height = gen.height();
|
||||
|
||||
|
@ -1973,10 +1945,6 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
|
|||
gen.add_n_blocks(30); /// generate some outputs and unlock them
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
crypto::ed25519_public_key pkey;
|
||||
crypto::ed25519_secret_key skey;
|
||||
crypto_sign_ed25519_seed_keypair(pkey.data, skey.data, reinterpret_cast<const unsigned char *>(miner.get_keys().m_spend_secret_key.data));
|
||||
|
||||
auto make_lns_tx_with_custom_extra = [&](loki_chain_generator &gen,
|
||||
std::vector<test_event_entry> &events,
|
||||
cryptonote::account_base const &src,
|
||||
|
@ -2000,16 +1968,16 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
|
|||
gen.add_tx(tx, true /*can_be_added_to_blockchain*/, "", false /*kept_by_block*/);
|
||||
};
|
||||
|
||||
lns_keys_t miner_key = make_lns_keys(miner);
|
||||
cryptonote::tx_extra_loki_name_system data = {};
|
||||
data.owner = pkey;
|
||||
data.value = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false, miner.get_keys().m_account_address);
|
||||
data.owner = miner_key.ed_key;
|
||||
|
||||
// Blockchain
|
||||
if (lns_mapping_type_enabled(lns::mapping_type::blockchain))
|
||||
{
|
||||
data.type = static_cast<uint16_t>(lns::mapping_type::blockchain);
|
||||
data.name = std::string(lns::BLOCKCHAIN_NAME_MAX, 'A');
|
||||
data.value = miner.get_public_address_str(cryptonote::FAKECHAIN);
|
||||
data.value = miner_key.blockchain_value;
|
||||
make_lns_tx_with_custom_extra(gen, events, miner, data);
|
||||
}
|
||||
|
||||
|
@ -2018,7 +1986,7 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
|
|||
{
|
||||
data.type = static_cast<uint16_t>(lns::mapping_type::lokinet);
|
||||
data.name = "doyle.loki";
|
||||
data.value = std::string(lns::LOKINET_ADDRESS_BINARY_LENGTH * 2, 'a');
|
||||
data.value = std::string(lns::LOKINET_ADDRESS_BINARY_LENGTH, 'a');
|
||||
make_lns_tx_with_custom_extra(gen, events, miner, data);
|
||||
}
|
||||
|
||||
|
@ -2026,7 +1994,7 @@ bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_en
|
|||
{
|
||||
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 * 2, 'a');
|
||||
data.value = std::string(lns::MESSENGER_PUBLIC_KEY_BINARY_LENGTH, 'a');
|
||||
data.value[0] = '0';
|
||||
data.value[1] = '5';
|
||||
make_lns_tx_with_custom_extra(gen, events, miner, data);
|
||||
|
@ -2070,17 +2038,17 @@ bool loki_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
|
|||
|
||||
if (type == lns::mapping_type::messenger)
|
||||
{
|
||||
value = lns_keys.messenger_value_hex;
|
||||
value = lns_keys.messenger_value;
|
||||
name = "My Friendly Messenger Name";
|
||||
}
|
||||
else if (type == lns::mapping_type::blockchain)
|
||||
{
|
||||
value = lns_keys.blockchain_value_hex;
|
||||
value = lns_keys.blockchain_value;
|
||||
name = "My Friendly Wallet Name";
|
||||
}
|
||||
else if (type == lns::mapping_type::lokinet)
|
||||
{
|
||||
value = lns_keys.lokinet_value_hex;
|
||||
value = lns_keys.lokinet_value;
|
||||
name = "MyFriendlyLokinetName.loki";
|
||||
}
|
||||
else
|
||||
|
|
|
@ -13,52 +13,52 @@ TEST(loki_name_system, lokinet_domain_names)
|
|||
// Should work
|
||||
{
|
||||
char const name[] = "mydomain.loki";
|
||||
ASSERT_TRUE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_TRUE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "a.loki";
|
||||
ASSERT_TRUE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_TRUE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "xn--bcher-kva.loki";
|
||||
ASSERT_TRUE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_TRUE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
// Should fail
|
||||
{
|
||||
char const name[] = "";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "mydomain.loki.example";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "mydomain.loki.com";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "mydomain.com";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "mydomain";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "xn--bcher-kva.lok";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
|
||||
{
|
||||
char const name[] = "a_b_c.loki";
|
||||
ASSERT_FALSE(lns::validate_lns_name_and_value(cryptonote::MAINNET, lokinet, name, loki::char_count(name), domain_edkeys, loki::array_count(domain_edkeys)));
|
||||
ASSERT_FALSE(lns::validate_lns_name(lokinet, name, loki::char_count(name)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue