Add txid/prev_txid into LNS db for rollbacks

This commit is contained in:
Doyle 2020-02-04 14:00:53 +11:00
parent e050b53c66
commit c4a9c7ab20
9 changed files with 206 additions and 108 deletions

View File

@ -388,12 +388,14 @@ namespace cryptonote
uint16_t type;
std::string name;
std::string value; // binary format of the name->value mapping
crypto::hash prev_txid; // previous txid that purchased the mapping, only applicable if lokinet
BEGIN_SERIALIZE()
FIELD(owner);
FIELD(type);
FIELD(name);
FIELD(value);
FIELD(prev_txid); // TODO(doyle): Conditional serializing?
END_SERIALIZE()
};

View File

@ -411,12 +411,12 @@ bool Blockchain::load_missing_blocks_into_loki_subsystems()
return true;
}
static void add_tx_if_lns_to(uint8_t hf_version, cryptonote::network_type nettype, std::map<uint64_t, std::vector<cryptonote::tx_extra_loki_name_system>> &map, uint64_t height, cryptonote::transaction const &tx)
static void add_tx_if_lns_to(lns::name_system_db const &lns_db, uint8_t hf_version, std::map<uint64_t, std::vector<cryptonote::tx_extra_loki_name_system>> &map, uint64_t height, cryptonote::transaction const &tx)
{
if (tx.type == txtype::loki_name_system)
{
cryptonote::tx_extra_loki_name_system entry;
if (lns::validate_lns_tx(hf_version, nettype, tx, &entry))
if (lns_db.validate_lns_tx(hf_version, height, tx, &entry))
map[height].push_back(std::move(entry));
}
}
@ -641,7 +641,7 @@ bool Blockchain::init(BlockchainDB* db, sqlite3 *lns_db, const network_type nett
return false;
}
add_tx_if_lns_to(blk.major_version, nettype, m_lns_uncommitted_entries, height, tx);
add_tx_if_lns_to(m_lns_db, blk.major_version, m_lns_uncommitted_entries, height, tx);
}
}
}
@ -3424,7 +3424,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, &fail_reason))
if (!m_lns_db.validate_lns_tx(hf_version, get_current_blockchain_height(), 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;
@ -3445,60 +3445,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
}
if (m_lns_db.db)
{
lns::mapping_record mapping = m_lns_db.get_mapping(data.type, data.name.data(), data.name.size());
if (mapping)
{
if (data.type != static_cast<uint16_t>(lns::mapping_type::lokinet))
{
MERROR_VER("TX: " << tx.type << " " << get_transaction_hash(tx) << ", owner = " << data.owner
<< ", type = " << (int)data.type << ", name = " << data.name
<< ", non-lokinet entries can NOT be renewed.");
return false;
}
uint64_t renew_window = 0;
uint64_t expiry_blocks = lns::lokinet_expiry_blocks(nettype(), &renew_window);
uint64_t const renew_window_offset = expiry_blocks - renew_window;
uint64_t const min_renew_height = mapping.register_height + renew_window_offset;
if (min_renew_height >= get_current_blockchain_height())
return false; // Trying to renew too early
// LNS entry can be renewed, check that the request to renew originates from the owner of this mapping
lns::user_record requester = m_lns_db.get_user_by_key(data.owner);
if (!requester)
{
MERROR_VER("TX: " << tx.type << " " << get_transaction_hash(tx) << ", owner = " << data.owner
<< ", type = " << (int)data.type << ", name = " << data.name
<< " user does not exist, but trying to renew existing mapping, rejected.");
return false;
}
lns::user_record owner = m_lns_db.get_user_by_id(mapping.user_id);
if (!owner)
{
MERROR_VER("TX: " << tx.type << " " << get_transaction_hash(tx) << ", owner = " << data.owner
<< ", type = " << (int)data.type << ", name = " << data.name
<< " unexpected user_id = " << mapping.user_id << " does not exist");
return false;
}
if (requester.id != owner.id)
{
MERROR_VER("TX: " << tx.type << " " << get_transaction_hash(tx) << ", owner = " << data.owner
<< ", type = " << (int)data.type << ", name = " << data.name << " actual owner user_id = "
<< mapping.user_id << ", does not match requester's id = " << requester.id);
return false;
}
}
else
{
// No pre-existing mapping, user can request this LNS entry
}
}
}
}
else
@ -4323,7 +4269,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
only_txs.push_back(tx_pair.first);
if (!lns_entries_checkpointed)
add_tx_if_lns_to(bl.major_version, nettype(), m_lns_uncommitted_entries, new_height, tx_pair.first);
add_tx_if_lns_to(m_lns_db, bl.major_version, m_lns_uncommitted_entries, new_height, tx_pair.first);
}
if (!load_missing_blocks_into_loki_subsystems())

View File

@ -54,16 +54,25 @@ enum struct mapping_record_row
type,
name,
value,
txid,
prev_txid,
register_height,
user_id,
};
static void sql_copy_blob(sqlite3_stmt *statement, int row, void *dest, int dest_size)
static bool sql_copy_blob(sqlite3_stmt *statement, int row, void *dest, int dest_size)
{
void const *blob = sqlite3_column_blob(statement, row);
int blob_len = sqlite3_column_bytes(statement, row);
assert(blob_len == dest_size);
memcpy(dest, blob, std::min(dest_size, blob_len));
if (blob_len != dest_size)
{
LOG_PRINT_L0("Unexpected blob size=" << blob_len << ", in LNS DB does not match expected size=" << dest_size);
return false;
}
memcpy(dest, blob, blob_len);
return true;
}
static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type type, sqlite3_stmt *statement, void *context)
@ -90,7 +99,8 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
{
auto *entry = reinterpret_cast<user_record *>(context);
entry->id = sqlite3_column_int(statement, static_cast<int>(user_record_row::id));
sql_copy_blob(statement, static_cast<int>(user_record_row::public_key), entry->key.data, sizeof(entry->key.data));
if (!sql_copy_blob(statement, static_cast<int>(user_record_row::public_key), entry->key.data, sizeof(entry->key.data)))
return false;
data_loaded = true;
}
break;
@ -99,7 +109,8 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
{
auto *entry = reinterpret_cast<settings_record *>(context);
entry->top_height = static_cast<uint64_t>(sqlite3_column_int64(statement, static_cast<int>(lns_db_setting_row::top_height)));
sql_copy_blob(statement, static_cast<int>(lns_db_setting_row::top_hash), entry->top_hash.data, sizeof(entry->top_hash.data));
if (!sql_copy_blob(statement, static_cast<int>(lns_db_setting_row::top_hash), entry->top_hash.data, sizeof(entry->top_hash.data)))
return false;
entry->version = sqlite3_column_int(statement, static_cast<int>(lns_db_setting_row::version));
data_loaded = true;
}
@ -121,8 +132,14 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
tmp_entry.name = std::string(name, name_len);
tmp_entry.value = std::string(value, value_len);
data_loaded = true;
if (!sql_copy_blob(statement, static_cast<int>(mapping_record_row::txid), tmp_entry.txid.data, sizeof(tmp_entry.txid)))
return false;
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)
{
auto *records = reinterpret_cast<std::vector<mapping_record> *>(context);
@ -498,7 +515,89 @@ bool validate_lns_value_binary(uint16_t type, char const *value, int value_len,
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)
static std::stringstream &error_stream_append_tx_msg(std::stringstream &err_stream, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system const &data)
{
err_stream << "TX type=" << tx.type << ", tx=" << get_transaction_hash(tx) << ", owner=" << data.owner << ", type=" << (int)data.type << ", name=" << data.name << ", ";
return err_stream;
}
static bool validate_against_previous_mapping(lns::name_system_db const &lns_db, uint64_t blockchain_height, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system const &data, std::string *reason = nullptr)
{
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()))
{
expected_prev_txid = mapping.txid;
if (data.type != static_cast<uint16_t>(lns::mapping_type::lokinet))
{
if (reason)
{
error_stream_append_tx_msg(err_stream, tx, data) << "non-lokinet entries can NOT be renewed.";
*reason = err_stream.str();
}
return false;
}
uint64_t renew_window = 0;
uint64_t expiry_blocks = lns::lokinet_expiry_blocks(lns_db.network_type(), &renew_window);
uint64_t const renew_window_offset = expiry_blocks - renew_window;
uint64_t const min_renew_height = mapping.register_height + renew_window_offset;
if (min_renew_height >= blockchain_height)
{
error_stream_append_tx_msg(err_stream, tx, data) << "user does not exist, but trying to renew existing mapping, rejected.";
*reason = err_stream.str();
return false; // Trying to renew too early
}
// LNS entry can be renewed, check that the request to renew originates from the owner of this mapping
lns::user_record requester = lns_db.get_user_by_key(data.owner);
if (!requester)
{
if (reason)
{
error_stream_append_tx_msg(err_stream, tx, data) << "user does not exist, but trying to renew existing mapping, rejected.";
*reason = err_stream.str();
}
return false;
}
lns::user_record owner = lns_db.get_user_by_id(mapping.user_id);
if (!owner)
{
if (reason)
{
error_stream_append_tx_msg(err_stream, tx, data) << "unexpected user_id=" << mapping.user_id << " does not exist";
*reason = err_stream.str();
}
return false;
}
if (requester.id != owner.id)
{
if (reason)
{
error_stream_append_tx_msg(err_stream, tx, data) << " actual owner user_id=" << mapping.user_id << ", does not match requester's id=" << requester.id;
*reason = err_stream.str();
}
return false;
}
}
if (data.prev_txid != expected_prev_txid)
{
if (reason)
{
error_stream_append_tx_msg(err_stream, tx, data) << " specified prior owner txid=" << data.prev_txid << ", but LNS DB reports=" << expected_prev_txid << ", possible competing TX was submitted and accepted before this TX was processed";
*reason = err_stream.str();
}
return false;
}
return true;
}
bool name_system_db::validate_lns_tx(uint8_t hf_version, uint64_t blockchain_height, cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system *entry, std::string *reason) const
{
cryptonote::tx_extra_loki_name_system entry_;
if (!entry) entry = &entry_;
@ -531,6 +630,9 @@ bool validate_lns_tx(uint8_t hf_version, cryptonote::network_type nettype, crypt
if (!validate_lns_value_binary(entry->type, entry->value.data(), static_cast<int>(entry->value.size()), 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);
if (burn != burn_required)
{
@ -600,6 +702,8 @@ CREATE TABLE IF NOT EXISTS "mappings" (
"type" INTEGER NOT NULL,
"name" VARCHAR NOT NULL,
"value" BLOB NOT NULL,
"txid" BLOB NOT NULL,
"prev_txid" BLOB NOT NULL,
"register_height" INTEGER NOT NULL,
"user_id" INTEGER NOT NULL REFERENCES "user" ("id")
);
@ -633,7 +737,7 @@ bool name_system_db::init(cryptonote::network_type nettype, sqlite3 *db, uint64_
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 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", "register_height", "user_id") VALUES (?,?,?,?,?))";
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 (?);)";
if (!build_default_tables(db))
@ -741,33 +845,31 @@ bool name_system_db::add_block(const cryptonote::block &block, const std::vector
cryptonote::tx_extra_loki_name_system entry = {};
std::string fail_reason;
if (!validate_lns_tx(block.major_version, nettype, tx, &entry, &fail_reason))
if (!validate_lns_tx(block.major_version, height, tx, &entry, &fail_reason))
{
LOG_PRINT_L0("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);
return false;
}
crypto::hash const &tx_hash = cryptonote::get_transaction_hash(tx);
int64_t user_id = 0;
if (user_record user = get_user_by_key(entry.owner)) user_id = user.id;
if (user_id == 0)
{
if (!save_user(entry.owner, &user_id))
{
LOG_PRINT_L1("Failed to save LNS user to DB tx: " << cryptonote::get_transaction_hash(tx) << ", type: " << (uint16_t)entry.type << ", name: " << entry.name << ", user: " << entry.owner);
LOG_PRINT_L1("Failed to save LNS user to DB tx: " << tx_hash << ", type: " << (uint16_t)entry.type << ", name: " << entry.name << ", user: " << entry.owner);
return false;
}
}
assert(user_id != 0);
if (!save_mapping(static_cast<uint16_t>(entry.type), entry.name, entry.value, height, user_id))
if (!save_mapping(tx_hash, entry, height, user_id))
{
LOG_PRINT_L1("Failed to save LNS entry to DB tx: " << cryptonote::get_transaction_hash(tx)
<< ", type: " << (uint16_t)entry.type
<< ", name: " << entry.name << ", user: " << entry.owner);
LOG_PRINT_L1("Failed to save LNS entry to DB tx: " << tx_hash << ", type: " << (uint16_t)entry.type << ", name: " << entry.name << ", user: " << entry.owner);
return false;
}
}
if (!expire_mappings(height))
@ -794,12 +896,14 @@ 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, std::string const &value, uint64_t height, int64_t user_id)
bool name_system_db::save_mapping(crypto::hash const &tx_hash, cryptonote::tx_extra_loki_name_system const &src, uint64_t height, int64_t user_id)
{
sqlite3_stmt *statement = save_mapping_sql;
sqlite3_bind_int (statement, static_cast<int>(mapping_record_row::type), type);
sqlite3_bind_text (statement, static_cast<int>(mapping_record_row::name), name.data(), name.size(), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::value), value.data(), value.size(), nullptr /*destructor*/);
sqlite3_bind_int (statement, static_cast<int>(mapping_record_row::type), static_cast<uint16_t>(src.type));
sqlite3_bind_text (statement, static_cast<int>(mapping_record_row::name), src.name.data(), src.name.size(), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::value), src.value.data(), src.value.size(), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::txid), tx_hash.data, sizeof(tx_hash), nullptr /*destructor*/);
sqlite3_bind_blob (statement, static_cast<int>(mapping_record_row::prev_txid), src.prev_txid.data, sizeof(src.prev_txid), nullptr /*destructor*/);
sqlite3_bind_int64(statement, static_cast<int>(mapping_record_row::register_height), static_cast<int64_t>(height));
sqlite3_bind_int64(statement, static_cast<int>(mapping_record_row::user_id), user_id);
bool result = sql_run_statement(nettype, lns_sql_type::save_mapping, statement, nullptr);

View File

@ -43,7 +43,6 @@ bool validate_lns_name(uint16_t type, char const *name, int name_len, st
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);
struct user_record
@ -68,9 +67,9 @@ struct settings_record
enum struct mapping_type : uint16_t
{
messenger = 0,
start_reserved = 1,
blockchain = 2,
lokinet = 3,
blockchain = 1,
lokinet = 2,
start_reserved = 3,
end_reserved = 64,
};
@ -79,11 +78,13 @@ struct mapping_record
operator bool() const { return loaded; }
bool loaded;
uint16_t type; // alias to lns::mapping_type
std::string name;
std::string value;
uint64_t register_height;
int64_t user_id;
uint16_t type; // alias to lns::mapping_type
std::string name;
std::string value;
uint64_t register_height;
int64_t user_id;
crypto::hash txid;
crypto::hash prev_txid;
};
struct name_system_db
@ -93,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, std::string const &value, uint64_t height, int64_t user_id);
bool save_mapping (crypto::hash const &tx_hash, cryptonote::tx_extra_loki_name_system const &src, 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);
@ -107,6 +108,9 @@ struct name_system_db
std::vector<mapping_record> get_mappings_by_user(crypto::ed25519_public_key const &key) 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;
cryptonote::network_type network_type() const { return nettype; }
sqlite3 *db = nullptr;
bool transaction_begun = false;
private:

View File

@ -3360,11 +3360,13 @@ namespace cryptonote
{
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.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 = mapping.txid;
entry.prev_txid = mapping.prev_txid;
}
else
{
@ -3404,10 +3406,12 @@ namespace cryptonote
{
entry.mappings.emplace_back();
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;
mapping.register_height = db_mapping.register_height;
mapping.type = db_mapping.type;
mapping.name = db_mapping.name;
mapping.pubkey = db_mapping.value;
mapping.register_height = db_mapping.register_height;
mapping.txid = db_mapping.txid;
mapping.prev_txid = db_mapping.prev_txid;
}
}
}

View File

@ -3442,17 +3442,21 @@ 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
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
crypto::hash txid; // The txid of who purchased the mapping (only applicable to Lokinet and if the Lokinet entry previously existed), null hash if not applicable
crypto::hash 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
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(entry_index)
KV_SERIALIZE(type)
KV_SERIALIZE(owner)
KV_SERIALIZE(pubkey)
KV_SERIALIZE(register_height)
KV_SERIALIZE_VAL_POD_AS_BLOB(txid)
KV_SERIALIZE_VAL_POD_AS_BLOB(prev_txid)
END_KV_SERIALIZE_MAP()
};
@ -3484,15 +3488,18 @@ 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)
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.
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain.
uint16_t type; // The cateogry the Loki Name Service entry belongs to (blockchain = 0, lokinet = 1, messenger = 2, otherwise custom)
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.
uint64_t register_height; // The height that this Loki Name Service entry was purchased on the Blockchain.
crypto::hash txid; // The height that this Loki Name Service entry was purchased on the Blockchain.
crypto::hash 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
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type)
KV_SERIALIZE(name)
KV_SERIALIZE(pubkey)
KV_SERIALIZE(register_height)
KV_SERIALIZE_VAL_POD_AS_BLOB(txid)
KV_SERIALIZE_VAL_POD_AS_BLOB(prev_txid)
END_KV_SERIALIZE_MAP()
};

View File

@ -8585,6 +8585,27 @@ std::vector<wallet2::pending_tx> wallet2::create_buy_lns_mapping_tx(uint16_t typ
entry.type = type;
entry.name = name;
entry.value.resize(value_blob.len);
if (type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
std::vector<cryptonote::COMMAND_RPC_GET_LNS_NAMES_TO_OWNERS::request_entry> request = {};
{
request.emplace_back();
auto request_entry = request.back();
request_entry.name = name;
request_entry.types.push_back(type);
}
boost::optional<std::string> failed;
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;
return {};
}
entry.prev_txid = response.empty() ? crypto::null_hash : response[0].txid;
}
memcpy(&entry.value[0], value_blob.buffer.data(), value_blob.len);
std::vector<uint8_t> extra;

View File

@ -548,9 +548,16 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(crypton
data.type = type;
data.value = value;
data.name = name;
if (type == static_cast<uint16_t>(lns::mapping_type::lokinet))
{
if (lns::mapping_record mapping = lns_db_.get_mapping(type, name))
data.prev_txid = mapping.txid;
else
data.prev_txid = crypto::null_hash;
}
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
cryptonote::add_burned_amount_to_tx_extra(extra, burn);
cryptonote::transaction result = {};
loki_tx_builder(events_, result, head, src /*from*/, src.get_keys().m_account_address, 0 /*amount*/, new_hf_version)
.with_tx_type(cryptonote::txtype::loki_name_system)

View File

@ -1863,6 +1863,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
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, name);
gen.create_and_add_next_block({tx});
crypto::hash prev_txid = get_transaction_hash(tx);
uint64_t height_of_lns_entry = gen.height();
uint64_t renew_window = 0;
@ -1892,6 +1893,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
CHECK_EQ(mappings.name, std::string(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);
CHECK_EQ(mappings.user_id, user.id);
return true;
});
@ -1912,7 +1914,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
gen.create_and_add_next_block();
loki_register_callback(events, "check_renewed", [&events, renewal_height, miner_key, name](cryptonote::core &c, size_t ev_index)
loki_register_callback(events, "check_renewed", [&events, renewal_height, miner_key, name, prev_txid](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_renewed");
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
@ -1928,6 +1930,7 @@ bool loki_name_system_name_renewal::generate(std::vector<test_event_entry> &even
CHECK_EQ(mappings.name, std::string(name));
CHECK_EQ(mappings.value, miner_key.lokinet_value);
CHECK_EQ(mappings.register_height, renewal_height);
CHECK_EQ(mappings.prev_txid, prev_txid);
CHECK_EQ(mappings.user_id, user.id);
return true;
});