Update SQL commands to handle backup owner keys

This commit is contained in:
Doyle 2020-02-26 17:29:41 +11:00
parent 43f7119cb1
commit aefdbbcae4
8 changed files with 329 additions and 48 deletions

View File

@ -401,7 +401,7 @@ namespace cryptonote
lns::tx_command command;
crypto::generic_public_key owner = {}; // only serialized if command == tx_command::buy
crypto::generic_public_key backup_owner = {}; // only serialized if command == tx_command::buy
crypto::generic_signature signature; // only serialized if command == tx_command::update
crypto::generic_signature signature = {}; // only serialized if command == tx_command::update
crypto::hash name_hash;
std::string encrypted_value; // encrypted binary format of the value in the name->value mapping
crypto::hash prev_txid = crypto::null_hash; // previous txid that purchased the mapping

View File

@ -69,6 +69,7 @@ enum struct mapping_record_row
prev_txid,
register_height,
owner_id,
backup_owner_id,
_count,
};
@ -139,9 +140,10 @@ static bool sql_run_statement(cryptonote::network_type nettype, lns_sql_type typ
if (type_int >= tools::enum_count<mapping_type>)
return false;
tmp_entry.type = static_cast<mapping_type>(type_int);
tmp_entry.type = static_cast<mapping_type>(type_int);
tmp_entry.register_height = static_cast<uint16_t>(sqlite3_column_int(statement, static_cast<int>(mapping_record_row::register_height)));
tmp_entry.owner_id = sqlite3_column_int(statement, static_cast<int>(mapping_record_row::owner_id));
tmp_entry.owner_id = sqlite3_column_int(statement, static_cast<int>(mapping_record_row::owner_id));
tmp_entry.backup_owner_id = sqlite3_column_int(statement, static_cast<int>(mapping_record_row::backup_owner_id));
// Copy encrypted_value
{
@ -169,10 +171,16 @@ 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;
int last_column = tools::enum_count<mapping_record_row> + 1;
if (!sql_copy_blob(statement, last_column, tmp_entry.owner.data, sizeof(tmp_entry.owner)))
int owner_column = tools::enum_count<mapping_record_row>;
if (!sql_copy_blob(statement, owner_column, tmp_entry.owner.data, sizeof(tmp_entry.owner)))
return false;
if (tmp_entry.backup_owner_id > 0)
{
if (!sql_copy_blob(statement, owner_column + 1, tmp_entry.backup_owner.data, sizeof(tmp_entry.backup_owner)))
return false;
}
data_loaded = true;
if (type == lns_sql_type::get_mapping)
{
@ -659,7 +667,7 @@ static bool validate_against_previous_mapping(lns::name_system_db const &lns_db,
// Validate signature
{
crypto::hash hash = tx_extra_signature_hash(epee::span<const uint8_t>(reinterpret_cast<const uint8_t *>(data.encrypted_value.data()), data.encrypted_value.size()), expected_prev_txid);
crypto::hash hash = tx_extra_signature_hash(epee::strspan<uint8_t>(data.encrypted_value), expected_prev_txid);
if (!verify_lns_signature(hash, data.signature, mapping.owner) && !verify_lns_signature(hash, data.signature, mapping.backup_owner))
{
if (reason)
@ -820,6 +828,18 @@ bool name_system_db::validate_lns_tx(uint8_t hf_version, uint64_t blockchain_hei
return false;
}
}
else
{
if (!entry->signature)
{
if (reason)
{
err_stream << tx << ", " << *entry << ", signature to validate is the null-signature";
*reason = err_stream.str();
}
return false;
}
}
if (!validate_encrypted_mapping_value(entry->type, entry->encrypted_value, reason))
return false;
@ -978,7 +998,8 @@ CREATE TABLE IF NOT EXISTS "mappings" (
"txid" BLOB NOT NULL,
"prev_txid" BLOB NOT NULL,
"register_height" INTEGER NOT NULL,
"owner_id" INTEGER NOT NULL REFERENCES "owner" ("id")
"owner_id" INTEGER NOT NULL REFERENCES "owner" ("id"),
"backup_owner_id" INTEGER REFERENCES "owner" ("id")
);
CREATE UNIQUE INDEX IF NOT EXISTS "name_hash_type_id" ON mappings("name_hash", "type");
)";
@ -1003,17 +1024,39 @@ bool name_system_db::init(cryptonote::network_type nettype, sqlite3 *db, uint64_
this->db = db;
this->nettype = nettype;
char constexpr GET_MAPPINGS_BY_OWNER_SQL[] = R"(SELECT * FROM "mappings" JOIN "owner" ON "mappings"."owner_id" = "owner"."id" WHERE "public_key" = ?)";
char constexpr GET_MAPPINGS_ON_HEIGHT_AND_NEWER_SQL[] = R"(SELECT * FROM "mappings" JOIN "owner" on "mappings"."owner_id" = "owner"."id" WHERE "register_height" >= ?)";
char constexpr GET_MAPPING_SQL[] = R"(SELECT * FROM "mappings" JOIN "owner" on "mappings"."owner_id" = "owner"."id" WHERE "type" = ? AND "name_hash" = ?)";
char constexpr GET_OWNER_BY_ID_SQL[] = R"(SELECT * FROM "owner" WHERE "id" = ?)";
char constexpr GET_OWNER_BY_KEY_SQL[] = R"(SELECT * FROM "owner" WHERE "public_key" = ?)";
char constexpr GET_SETTINGS_SQL[] = R"(SELECT * FROM "settings" WHERE "id" = 1)";
char constexpr PRUNE_MAPPINGS_SQL[] = R"(DELETE FROM "mappings" WHERE "register_height" >= ?)";
char constexpr PRUNE_OWNERS_SQL[] = R"(DELETE FROM "owner" WHERE "id" NOT IN (SELECT "owner_id" FROM "mappings"))";
char constexpr SAVE_MAPPING_SQL[] = R"(INSERT OR REPLACE INTO "mappings" ("type", "name_hash", "encrypted_value", "txid", "prev_txid", "register_height", "owner_id") VALUES (?,?,?,?,?,?,?))";
char constexpr SAVE_OWNER_SQL[] = R"(INSERT INTO "owner" ("public_key") VALUES (?);)";
char constexpr SAVE_SETTINGS_SQL[] = R"(INSERT OR REPLACE INTO "settings" ("id", "top_height", "top_hash", "version") VALUES (1,?,?,?))";
char constexpr GET_MAPPINGS_BY_OWNER_SQL[] =
R"(SELECT "mappings".*, "o1"."public_key", "o2"."public_key" FROM "mappings"
JOIN "owner" "o1" ON "mappings"."owner_id" = "o1"."id"
LEFT JOIN "owner" "o2" ON "mappings"."backup_owner_id" = "o2"."id"
WHERE "o1"."public_key" = ? OR "o2"."public_key" = ?)";
char constexpr GET_MAPPINGS_ON_HEIGHT_AND_NEWER_SQL[] =
R"(SELECT "mappings".*, "o1"."public_key", "o2"."public_key" FROM "mappings"
JOIN "owner" "o1" ON "mappings"."owner_id" = "o1"."id"
LEFT JOIN "owner" "o2" ON "mappings"."backup_owner_id" = "o2"."id"
WHERE "register_height" >= ?)";
char constexpr GET_MAPPING_SQL[] =
R"(SELECT "mappings".*, "o1"."public_key", "o2"."public_key" FROM "mappings"
JOIN "owner" "o1" ON "mappings"."owner_id" = "o1"."id"
LEFT JOIN "owner" "o2" ON "mappings"."backup_owner_id" = "o2"."id"
WHERE "type" = ? AND "name" = ?)";
char constexpr GET_OWNER_BY_ID_SQL[] = R"(SELECT * FROM "owner" WHERE "id" = ?)";
char constexpr GET_OWNER_BY_KEY_SQL[] = R"(SELECT * FROM "owner" WHERE "public_key" = ?)";
char constexpr GET_SETTINGS_SQL[] = R"(SELECT * FROM "settings" WHERE "id" = 1)";
char constexpr PRUNE_MAPPINGS_SQL[] = R"(DELETE FROM "mappings" WHERE "register_height" >= ?)";
char constexpr PRUNE_OWNERS_SQL[] =
R"(DELETE FROM "owner"
WHERE NOT EXISTS
(SELECT * FROM "mappings"
WHERE "owner"."id" = "mappings"."owner_id"
OR "owner"."id" = "mappings"."backup_owner_id"))";
char constexpr SAVE_MAPPING_SQL[] = R"(INSERT OR REPLACE INTO "mappings" ("type", "name", "value", "txid", "prev_txid", "register_height", "owner_id", "backup_owner_id") VALUES (?,?,?,?,?,?,?,?))";
char constexpr SAVE_OWNER_SQL[] = R"(INSERT INTO "owner" ("public_key") VALUES (?);)";
char constexpr SAVE_SETTINGS_SQL[] = R"(INSERT OR REPLACE INTO "settings" ("id", "top_height", "top_hash", "version") VALUES (1,?,?,?))";
sqlite3_stmt *test;
@ -1106,27 +1149,49 @@ scoped_db_transaction::~scoped_db_transaction()
lns_db.transaction_begun = false;
}
static bool add_lns_entry(lns::name_system_db &lns_db, uint64_t height, cryptonote::tx_extra_loki_name_system const &entry, crypto::hash const &tx_hash)
static int64_t add_or_get_owner_id(lns::name_system_db &lns_db, crypto::hash const &tx_hash, cryptonote::tx_extra_loki_name_system const &entry, crypto::generic_public_key const &key)
{
int64_t owner_id = 0;
if (owner_record owner = lns_db.get_owner_by_key(entry.owner)) owner_id = owner.id;
if (owner_id == 0)
int64_t result = 0;
if (owner_record owner = lns_db.get_owner_by_key(key)) result = owner.id;
if (result == 0)
{
if (entry.command == lns::tx_command::update)
{
MERROR("Owner does not exist but TX received is trying to update an existing mapping (i.e. owner should already exist). TX=" << tx_hash << " should have failed validation prior.");
return false;
return result;
}
if (!lns_db.save_owner(entry.owner, &owner_id))
if (!lns_db.save_owner(key, &result))
{
LOG_PRINT_L1("Failed to save LNS owner to DB tx: " << tx_hash << ", type: " << entry.type << ", name_hash: " << entry.name_hash << ", owner: " << entry.owner);
return result;
}
}
return result;
}
static bool add_lns_entry(lns::name_system_db &lns_db, uint64_t height, cryptonote::tx_extra_loki_name_system const &entry, crypto::hash const &tx_hash)
{
int64_t owner_id = add_or_get_owner_id(lns_db, tx_hash, entry, entry.owner);
if (owner_id == 0)
{
assert(owner_id != 0);
return false;
}
int64_t backup_owner_id = 0;
if (entry.backup_owner)
{
backup_owner_id = add_or_get_owner_id(lns_db, tx_hash, entry, entry.backup_owner);
if (backup_owner_id == 0)
{
assert(backup_owner_id != 0);
LOG_PRINT_L1("Failed to save LNS backup owner to DB tx: " << tx_hash << ", type: " << entry.type << ", name_hash: " << entry.name_hash << ", owner: " << entry.owner);
return false;
}
}
assert(owner_id != 0);
if (!lns_db.save_mapping(tx_hash, entry, height, owner_id))
if (!lns_db.save_mapping(tx_hash, entry, height, owner_id, backup_owner_id))
{
LOG_PRINT_L1("Failed to save LNS entry to DB tx: " << tx_hash << ", type: " << entry.type << ", name_hash: " << entry.name_hash << ", owner: " << entry.owner);
return false;
@ -1276,7 +1341,7 @@ bool name_system_db::save_owner(crypto::generic_public_key const &key, int64_t *
return result;
}
bool name_system_db::save_mapping(crypto::hash const &tx_hash, cryptonote::tx_extra_loki_name_system const &src, uint64_t height, int64_t owner_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 owner_id, int64_t backup_owner_id)
{
std::string name_hash = hash_to_base64(src.name_hash);
sqlite3_stmt *statement = save_mapping_sql;
@ -1287,6 +1352,10 @@ bool name_system_db::save_mapping(crypto::hash const &tx_hash, cryptonote::tx_ex
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::owner_id), owner_id);
if (backup_owner_id != 0)
{
sqlite3_bind_int64(statement, static_cast<int>(mapping_record_row::backup_owner_id), backup_owner_id);
}
bool result = sql_run_statement(nettype, lns_sql_type::save_mapping, statement, nullptr);
return result;
}
@ -1358,7 +1427,11 @@ std::vector<mapping_record> name_system_db::get_mappings(std::vector<uint16_t> c
if (types.size())
{
char constexpr SQL_PREFIX[] = R"(SELECT * FROM "mappings" JOIN "owner" ON "mappings"."owner_id" = "owner"."id" WHERE "name_hash" = ? AND "type" in ()";
char constexpr SQL_PREFIX[] =
R"(SELECT "mappings".*, "o1"."public_key", "o2"."public_key" FROM "mappings"
JOIN "owner" "o1" ON "mappings"."owner_id" = "o1"."id"
LEFT JOIN "owner" "o2" ON "mappings"."backup_owner_id" = "o2"."id"
WHERE "name" = ? AND "type" in ()";
char constexpr SQL_SUFFIX[] = R"())";
std::stringstream stream;
@ -1399,7 +1472,12 @@ std::vector<mapping_record> name_system_db::get_mappings_by_owners(std::vector<c
std::string sql_statement;
// Generate string statement
{
char constexpr SQL_PREFIX[] = R"(SELECT * FROM "mappings" JOIN "owner" ON "mappings"."owner_id" = "owner"."id" WHERE "public_key" in ()";
char constexpr SQL_PREFIX[] =
R"(SELECT "mappings".*, "o1"."public_key", "o2"."public_key" FROM "mappings"
JOIN "owner" "o1" ON "mappings"."owner_id" = "o1"."id"
LEFT JOIN "owner" "o2" ON "mappings"."backup_owner_id" = "o2"."id"
WHERE "o1"."public_key" in ()";
char constexpr SQL_MIDDLE[] = R"(OR "o2"."public_key" in ()";
char constexpr SQL_SUFFIX[] = R"())";
std::stringstream stream;
@ -1410,6 +1488,14 @@ std::vector<mapping_record> name_system_db::get_mappings_by_owners(std::vector<c
if (i < (keys.size() - 1)) stream << ", ";
}
stream << SQL_SUFFIX;
stream << SQL_MIDDLE;
for (size_t i = 0; i < keys.size(); i++)
{
stream << "?";
if (i < (keys.size() - 1)) stream << ", ";
}
stream << SQL_SUFFIX;
sql_statement = stream.str();
}
@ -1421,9 +1507,14 @@ std::vector<mapping_record> name_system_db::get_mappings_by_owners(std::vector<c
// Bind parameters statements
int sql_param_index = 1;
for (auto const &key : keys)
sqlite3_bind_blob(statement, sql_param_index++, key.data, sizeof(key), nullptr /*destructor*/);
assert((sql_param_index - 1) == static_cast<int>(keys.size()));
for (size_t i = 0; i < keys.size(); i++)
{
for (auto const &key : keys)
{
sqlite3_bind_blob(statement, sql_param_index++, key.data, sizeof(key), nullptr /*destructor*/);
}
}
assert((sql_param_index - 1) == (static_cast<int>(keys.size() * 2)));
// Execute
sql_run_statement(nettype, lns_sql_type::get_mappings_by_owners, statement, &result);
@ -1436,6 +1527,7 @@ std::vector<mapping_record> name_system_db::get_mappings_by_owner(crypto::generi
sqlite3_stmt *statement = get_mappings_by_owner_sql;
sqlite3_clear_bindings(statement);
sqlite3_bind_blob(statement, 1 /*sql param index*/, key.data, sizeof(key), nullptr /*destructor*/);
sqlite3_bind_blob(statement, 2 /*sql param index*/, key.data, sizeof(key), nullptr /*destructor*/);
sql_run_statement(nettype, lns_sql_type::get_mappings_by_owner, statement, &result);
return result;
}

View File

@ -123,12 +123,12 @@ struct mapping_record
std::string name_hash; // name hashed and represented in base64 encoding
mapping_value encrypted_value;
uint64_t register_height;
int64_t owner_id;
crypto::generic_public_key owner;
crypto::generic_public_key backup_owner;
int64_t backup_owner_id;
crypto::hash txid;
crypto::hash prev_txid;
int64_t owner_id;
int64_t backup_owner_id;
crypto::generic_public_key owner;
crypto::generic_public_key backup_owner;
};
struct name_system_db
@ -142,7 +142,7 @@ struct name_system_db
// Signifies the blockchain has reorganized commences the rollback and pruning procedures.
void block_detach(cryptonote::Blockchain const &blockchain, uint64_t new_blockchain_height);
bool save_owner (crypto::generic_public_key const &key, int64_t *row_id);
bool save_mapping (crypto::hash const &tx_hash, cryptonote::tx_extra_loki_name_system const &src, uint64_t height, int64_t owner_id);
bool save_mapping (crypto::hash const &tx_hash, cryptonote::tx_extra_loki_name_system const &src, uint64_t height, int64_t owner_id, int64_t backup_owner_id = 0);
bool save_settings (uint64_t top_height, crypto::hash const &top_hash, int version);
// Delete all mappings that are registered on height or newer followed by deleting all owners no longer referenced in the DB

View File

@ -288,9 +288,10 @@ loki_chain_generator::create_and_add_loki_name_system_tx(cryptonote::account_bas
lns::mapping_value const &value,
std::string const &name,
crypto::generic_public_key const *owner,
crypto::generic_public_key const *backup_owner,
bool kept_by_block)
{
cryptonote::transaction t = create_loki_name_system_tx(src, type, value, name, owner);
cryptonote::transaction t = create_loki_name_system_tx(src, type, value, name, owner, backup_owner);
add_tx(t, true /*can_be_added_to_blockchain*/, ""/*fail_msg*/, kept_by_block);
return t;
}
@ -300,9 +301,10 @@ loki_chain_generator::create_and_add_loki_name_system_tx_update(cryptonote::acco
lns::mapping_type type,
lns::mapping_value const &value,
std::string const &name,
crypto::generic_signature *signature,
bool kept_by_block)
{
cryptonote::transaction t = create_loki_name_system_tx_update(src, type, value, name);
cryptonote::transaction t = create_loki_name_system_tx_update(src, type, value, name, signature);
add_tx(t, true /*can_be_added_to_blockchain*/, ""/*fail_msg*/, kept_by_block);
return t;
}
@ -518,6 +520,7 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(crypton
lns::mapping_value const &value,
std::string const &name,
crypto::generic_public_key const *owner,
crypto::generic_public_key const *backup_owner,
uint64_t burn) const
{
crypto::generic_public_key pkey;
@ -547,7 +550,7 @@ cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(crypton
assert(encrypted);
std::vector<uint8_t> extra;
cryptonote::tx_extra_loki_name_system data = cryptonote::tx_extra_loki_name_system::make_buy(pkey, nullptr, type, name_hash, encrypted_value.to_string(), prev_txid);
cryptonote::tx_extra_loki_name_system data = cryptonote::tx_extra_loki_name_system::make_buy(pkey, backup_owner, type, name_hash, encrypted_value.to_string(), prev_txid);
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
cryptonote::add_burned_amount_to_tx_extra(extra, burn);
cryptonote::transaction result = {};

View File

@ -1421,9 +1421,8 @@ struct loki_chain_generator
// NOTE: Add constructed TX to events_ and assume that it is valid to add to the blockchain. If the TX is meant to be unaddable to the blockchain use the individual create + add functions to
// be able to mark the add TX event as something that should trigger a failure.
// value: The binary representation of the value part in the name->value mapping
cryptonote::transaction create_and_add_loki_name_system_tx(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::generic_public_key const *owner = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, bool kept_by_block = false);
cryptonote::transaction create_and_add_loki_name_system_tx(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::generic_public_key const *owner = nullptr, crypto::generic_public_key const *backup_owner = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::generic_signature *signature = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_tx (const cryptonote::account_base& src, const cryptonote::account_public_address& dest, uint64_t amount, uint64_t fee = TESTS_DEFAULT_FEE, bool kept_by_block = false);
cryptonote::transaction create_and_add_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, bool kept_by_block = false);
cryptonote::transaction create_and_add_registration_tx(const cryptonote::account_base& src, const cryptonote::keypair& sn_keys = cryptonote::keypair::generate(hw::get_device("default")), bool kept_by_block = false);
@ -1444,7 +1443,7 @@ struct loki_chain_generator
// 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, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::generic_public_key const *owner = nullptr, uint64_t burn = LNS_AUTO_BURN) const;
cryptonote::transaction create_loki_name_system_tx(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::generic_public_key const *owner = nullptr, crypto::generic_public_key const *backup_owner = nullptr, uint64_t burn = LNS_AUTO_BURN) const;
cryptonote::transaction create_loki_name_system_tx_update(cryptonote::account_base const &src, lns::mapping_type type, lns::mapping_value const &value, std::string const &name, crypto::generic_signature *signature = nullptr, bool use_asserts = false) const;
cryptonote::transaction create_loki_name_system_tx_update_w_extra(cryptonote::account_base const &src, cryptonote::tx_extra_loki_name_system const &lns_extra) const;

View File

@ -136,6 +136,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(loki_name_system_name_value_max_lengths);
GENERATE_AND_PLAY(loki_name_system_update_mapping_after_expiry_fails);
GENERATE_AND_PLAY(loki_name_system_update_mapping);
GENERATE_AND_PLAY(loki_name_system_update_mapping_multiple_owners);
GENERATE_AND_PLAY(loki_name_system_update_mapping_non_existent_name_fails);
GENERATE_AND_PLAY(loki_name_system_update_mapping_invalid_signature);
GENERATE_AND_PLAY(loki_name_system_update_mapping_replay);

View File

@ -1176,9 +1176,9 @@ bool loki_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
uint64_t wallet_height = gen.height();
loki_register_callback(events, "check_lns_entries", [&events, bob_key,
wallet_height, wallet_name1, wallet_name2,
session_height, session_name1, session_name2,
lokinet_height, lokinet_name1, lokinet_name2
wallet_height, wallet_name1, wallet_name2,
session_height, session_name1, session_name2,
lokinet_height, lokinet_name1, lokinet_name2
](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_lns_entries");
@ -2147,6 +2147,191 @@ bool loki_name_system_update_mapping::generate(std::vector<test_event_entry> &ev
return true;
}
bool loki_name_system_update_mapping_multiple_owners::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);
gen.add_blocks_until_version(hard_forks.back().first);
gen.add_n_blocks(10); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
cryptonote::account_base miner = gen.first_miner_;
lns_keys_t miner_key = make_lns_keys(miner);
// Test 2 ed keys as owner
{
crypto::hash prev_txid = crypto::null_hash;
crypto::generic_public_key owner1;
crypto::generic_public_key owner2;
crypto::ed25519_secret_key owner1_key;
crypto::ed25519_secret_key owner2_key;
crypto_sign_ed25519_keypair(owner1.data, owner1_key.data);
crypto_sign_ed25519_keypair(owner2.data, owner2_key.data);
std::string name = "Hello World";
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(miner, lns::mapping_type::session, miner_key.session_value, name, &owner1, &owner2);
gen.create_and_add_next_block({tx1});
prev_txid = cryptonote::get_transaction_hash(tx1);
// Update with owner1
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto_sign_detached(signature.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash), owner1_key.data);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
// Update with owner2
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto_sign_detached(signature.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash), owner2_key.data);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
}
// Test 2 monero keys as owner
{
crypto::hash prev_txid = crypto::null_hash;
crypto::generic_public_key owner1;
crypto::generic_public_key owner2;
crypto::secret_key owner1_key;
crypto::secret_key owner2_key;
crypto::generate_keys(owner1.monero, owner1_key);
crypto::generate_keys(owner2.monero, owner2_key);
std::string name = "Hello Sailor";
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(miner, lns::mapping_type::session, miner_key.session_value, name, &owner1, &owner2);
gen.create_and_add_next_block({tx1});
prev_txid = cryptonote::get_transaction_hash(tx1);
// Update with owner1
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto::generate_signature(hash, owner1.monero, owner1_key, signature.monero);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
// Update with owner2
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto::generate_signature(hash, owner2.monero, owner2_key, signature.monero);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
}
// Test 1 ed/1 monero as owner
{
crypto::hash prev_txid = crypto::null_hash;
crypto::generic_public_key owner1;
crypto::generic_public_key owner2;
crypto::ed25519_secret_key owner1_key;
crypto::secret_key owner2_key;
crypto_sign_ed25519_keypair(owner1.data, owner1_key.data);
crypto::generate_keys(owner2.monero, owner2_key);
std::string name = "Hello Driver";
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(miner, lns::mapping_type::session, miner_key.session_value, name, &owner1, &owner2);
gen.create_and_add_next_block({tx1});
prev_txid = cryptonote::get_transaction_hash(tx1);
// Update with owner1
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto_sign_detached(signature.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash), owner1_key.data);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
// Update with owner2
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto::generate_signature(hash, owner2.monero, owner2_key, signature.monero);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
}
// Test 1 monero/1 ed as owner
{
crypto::hash prev_txid = crypto::null_hash;
crypto::generic_public_key owner1;
crypto::generic_public_key owner2;
crypto::secret_key owner1_key;
crypto::ed25519_secret_key owner2_key;
crypto::generate_keys(owner1.monero, owner1_key);
crypto_sign_ed25519_keypair(owner2.data, owner2_key.data);
std::string name = "Hello Passenger";
cryptonote::transaction tx1 = gen.create_and_add_loki_name_system_tx(miner, lns::mapping_type::session, miner_key.session_value, name, &owner1, &owner2);
gen.create_and_add_next_block({tx1});
prev_txid = cryptonote::get_transaction_hash(tx1);
// Update with owner1
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto::generate_signature(hash, owner1.monero, owner1_key, signature.monero);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
// Update with owner2
{
lns_keys_t temp_keys = make_lns_keys(gen.add_account());
crypto::generic_signature signature;
crypto::hash hash = lns::tx_extra_signature_hash(temp_keys.session_value.to_span(), prev_txid);
crypto_sign_detached(signature.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash), owner2_key.data);
cryptonote::transaction tx2 = gen.create_and_add_loki_name_system_tx_update(miner, lns::mapping_type::session, temp_keys.session_value, name, &signature);
gen.create_and_add_next_block({tx2});
prev_txid = cryptonote::get_transaction_hash(tx2);
}
}
return true;
}
bool loki_name_system_update_mapping_non_existent_name_fails::generate(std::vector<test_event_entry> &events)
{
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
@ -2282,7 +2467,7 @@ bool loki_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
if (under_burn) burn -= 1;
else burn += 1;
cryptonote::transaction tx = gen.create_loki_name_system_tx(miner, type, value, name, nullptr /*owner*/, burn);
cryptonote::transaction tx = gen.create_loki_name_system_tx(miner, type, value, name, nullptr /*owner*/, nullptr /*backup_owner*/, burn);
gen.add_tx(tx, false /*can_be_added_to_blockchain*/, "Wrong burn for a LNS tx", false /*kept_by_block*/);
}
}

View File

@ -64,6 +64,7 @@ struct loki_name_system_name_renewal
struct loki_name_system_name_value_max_lengths : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_update_mapping_after_expiry_fails : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_update_mapping : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_update_mapping_multiple_owners : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_update_mapping_non_existent_name_fails : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_update_mapping_invalid_signature : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_update_mapping_replay : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };