Add support for Loki Name Service on the backend

This commit is contained in:
Doyle 2019-11-01 11:58:48 +11:00
parent 623a354118
commit dc69d237e6
40 changed files with 1532 additions and 180 deletions

View File

@ -480,7 +480,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, net_type);
r = core_storage->init(db, nullptr /*lns_db*/, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");

View File

@ -162,7 +162,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, net_type);
r = core_storage->init(db, nullptr /*lns_db*/, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");

View File

@ -162,7 +162,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET);
r = core_storage->init(db, nullptr, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET);
if (core_storage->get_blockchain_pruning_seed())
{

View File

@ -597,7 +597,7 @@ int main(int argc, char* argv[])
MERROR("Error opening database: " << e.what());
return 1;
}
r = core_storage[n]->init(db, net_type);
r = core_storage[n]->init(db, nullptr /*lns_db*/, net_type);
std::string source_dest = n == 0 ? "source" : "pruned";
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize " << source_dest << " blockchain storage");

View File

@ -202,7 +202,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, net_type);
r = core_storage->init(db, nullptr /*lns_db*/, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");

View File

@ -160,7 +160,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, net_type);
r = core_storage->init(db, nullptr /*lns_db*/, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");

View File

@ -191,7 +191,8 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, net_type);
r = core_storage->init(db, nullptr /*lns_db*/, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");

View File

@ -38,6 +38,7 @@
extern "C"
{
#include "crypto/keccak.h"
#include "sodium.h"
}
#include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h"
@ -54,7 +55,12 @@ DISABLE_VS_WARNINGS(4244 4345)
namespace cryptonote
{
static void generate_ed25519_keys(account_keys &keys)
{
crypto::secret_key const &spend_key = keys.m_spend_secret_key;
crypto::ec_scalar const &spend_key_unwrapped = unwrap(unwrap(keys.m_spend_secret_key));
crypto_sign_ed25519_seed_keypair(keys.m_spend_ed25519_public_key.data, keys.m_spend_ed25519_secret_key.data, reinterpret_cast<unsigned char const *>(spend_key_unwrapped.data));
}
//-----------------------------------------------------------------
hw::device& account_keys::get_device() const {
return *m_device;
@ -101,6 +107,8 @@ DISABLE_VS_WARNINGS(4244 4345)
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
k.data[i] ^= *ptr++;
}
for (size_t i = 0; i < sizeof(m_spend_ed25519_secret_key); ++i)
m_spend_ed25519_secret_key.data[i] ^= *ptr++;
}
//-----------------------------------------------------------------
void account_keys::encrypt(const crypto::chacha_key &key)
@ -151,6 +159,7 @@ DISABLE_VS_WARNINGS(4244 4345)
//-----------------------------------------------------------------
void account_base::forget_spend_key()
{
sodium_memzero(m_keys.m_spend_ed25519_secret_key.data, sizeof(m_keys.m_spend_ed25519_secret_key));
m_keys.m_spend_secret_key = crypto::secret_key();
m_keys.m_multisig_keys.clear();
}
@ -183,6 +192,8 @@ DISABLE_VS_WARNINGS(4244 4345)
{
m_creation_timestamp = time(NULL);
}
generate_ed25519_keys(m_keys);
return first;
}
//-----------------------------------------------------------------
@ -203,6 +214,8 @@ DISABLE_VS_WARNINGS(4244 4345)
m_creation_timestamp = mktime(&timestamp);
if (m_creation_timestamp == (uint64_t)-1) // failure
m_creation_timestamp = 0; // lowest value
generate_ed25519_keys(m_keys);
}
//-----------------------------------------------------------------
@ -237,6 +250,8 @@ DISABLE_VS_WARNINGS(4244 4345)
m_creation_timestamp = mktime(&timestamp);
if (m_creation_timestamp == (uint64_t)-1) // failure
m_creation_timestamp = 0; // lowest value
generate_ed25519_keys(m_keys);
}
//-----------------------------------------------------------------
@ -253,12 +268,15 @@ DISABLE_VS_WARNINGS(4244 4345)
m_keys.m_view_secret_key = view_secret_key;
m_keys.m_spend_secret_key = spend_secret_key;
m_keys.m_multisig_keys = multisig_keys;
return crypto::secret_key_to_public_key(view_secret_key, m_keys.m_account_address.m_view_public_key);
bool result = crypto::secret_key_to_public_key(view_secret_key, m_keys.m_account_address.m_view_public_key);
generate_ed25519_keys(m_keys);
return result;
}
//-----------------------------------------------------------------
void account_base::finalize_multisig(const crypto::public_key &spend_public_key)
{
m_keys.m_account_address.m_spend_public_key = spend_public_key;
generate_ed25519_keys(m_keys);
}
//-----------------------------------------------------------------
const account_keys& account_base::get_keys() const

View File

@ -46,6 +46,10 @@ namespace cryptonote
hw::device *m_device = &hw::get_device("default");
crypto::chacha_iv m_encryption_iv;
// NOTE: Not serialized
crypto::ed25519_secret_key m_spend_ed25519_secret_key;
crypto::ed25519_public_key m_spend_ed25519_public_key;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_account_address)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)

View File

@ -169,6 +169,7 @@ namespace cryptonote
state_change,
key_image_unlock,
stake,
loki_name_system,
_count
};
@ -191,7 +192,7 @@ namespace cryptonote
txversion version;
txtype type;
bool is_transfer() const { return type == txtype::standard || type == txtype::stake; }
bool is_transfer() const { return type == txtype::standard || type == txtype::stake || type == txtype::loki_name_system; }
// not used after version 2, but remains for compatibility
uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
@ -557,7 +558,7 @@ namespace cryptonote
inline txtype transaction_prefix::get_max_type_for_hf(uint8_t hf_version)
{
txtype result = txtype::standard;
if (hf_version >= network_version_14_blink_lns) result = txtype::stake;
if (hf_version >= network_version_14_blink_lns) result = txtype::loki_name_system;
else if (hf_version >= network_version_11_infinite_staking) result = txtype::key_image_unlock;
else if (hf_version >= network_version_9_service_nodes) result = txtype::state_change;
return result;
@ -579,11 +580,12 @@ namespace cryptonote
{
switch(type)
{
case txtype::standard: return "standard";
case txtype::state_change: return "state_change";
case txtype::key_image_unlock: return "key_image_unlock";
case txtype::stake: return "stake";
default: assert(false); return "xx_unhandled_type";
case txtype::standard: return "standard";
case txtype::state_change: return "state_change";
case txtype::key_image_unlock: return "key_image_unlock";
case txtype::stake: return "stake";
case txtype::loki_name_system: return "loki_name_system";
default: assert(false); return "xx_unhandled_type";
}
}

View File

@ -43,6 +43,9 @@
#include "ringct/rctSigs.h"
#include "cryptonote_basic/verification_context.h"
#include "cryptonote_core/service_node_voting.h"
#include "cryptonote_core/loki_name_system_db.h"
#include <boost/endian/conversion.hpp>
using namespace epee;
@ -588,6 +591,7 @@ namespace cryptonote
if (!pick<tx_extra_service_node_contributor> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR)) return false;
if (!pick<tx_extra_service_node_pubkey> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY)) return false;
if (!pick<tx_extra_tx_secret_key> (nar, tx_extra_fields, TX_EXTRA_TAG_TX_SECRET_KEY)) return false;
if (!pick<tx_extra_loki_name_system> (nar, tx_extra_fields, TX_EXTRA_TAG_LOKI_NAME_SYSTEM)) return false;
if (!pick<tx_extra_tx_key_image_proofs> (nar, tx_extra_fields, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS)) return false;
if (!pick<tx_extra_tx_key_image_unlock> (nar, tx_extra_fields, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK)) return false;
@ -904,6 +908,46 @@ namespace cryptonote
return winner.m_service_node_key;
}
//---------------------------------------------------------------
crypto::hash tx_extra_loki_name_system::make_signature_hash() const
{
char buf[sizeof(owner.data) + sizeof(type) + lns::GENERIC_NAME_MAX + lns::GENERIC_VALUE_MAX] = {};
char *buf_ptr = buf;
memcpy(buf_ptr, owner.data, sizeof(owner));
buf_ptr += owner;
uint16_t type_le = boost::endian::native_to_little(type);
memcpy(buf_ptr, &type_le, sizeof(type_le));
buf_ptr += sizeof(type_le);
size_t bytes_to_copy = std::min(lns::GENERIC_NAME_MAX, name.size());
memcpy(buf_ptr, name.data(), bytes_to_copy);
buf_ptr += bytes_to_copy;
bytes_to_copy = std::min(lns::GENERIC_VALUE_MAX, value.size());
memcpy(buf_ptr, value.data(), bytes_to_copy);
buf_ptr += bytes_to_copy;
size_t buf_size = buf_ptr - buf;
crypto::hash result;
crypto::cn_fast_hash(buf, buf_size, result);
return result;
}
//---------------------------------------------------------------
bool get_loki_name_system_from_tx_extra(const std::vector<uint8_t> &tx_extra, tx_extra_loki_name_system &entry)
{
std::vector<tx_extra_field> tx_extra_fields;
parse_tx_extra(tx_extra, tx_extra_fields);
bool result = find_tx_extra_field_by_type(tx_extra_fields, entry);
return result;
}
//---------------------------------------------------------------
void add_loki_name_system_to_tx_extra(std::vector<uint8_t> &tx_extra, tx_extra_loki_name_system const &entry)
{
tx_extra_field field = entry;
add_tx_extra_field_to_tx_extra(tx_extra, field);
}
//---------------------------------------------------------------
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
{
if (tx_extra.empty())

View File

@ -112,6 +112,9 @@ namespace cryptonote
void add_service_node_contributor_to_tx_extra(std::vector<uint8_t>& tx_extra, const cryptonote::account_public_address& address);
crypto::public_key get_service_node_winner_from_tx_extra(const std::vector<uint8_t>& tx_extra);
bool get_loki_name_system_from_tx_extra(std::vector<uint8_t> const &tx_extra, tx_extra_loki_name_system &entry);
void add_loki_name_system_to_tx_extra (std::vector<uint8_t> &tx_extra, tx_extra_loki_name_system const &entry);
std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const std::vector<uint8_t>& tx_extra);
std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx);
bool add_additional_tx_pub_keys_to_extra(std::vector<uint8_t>& tx_extra, const std::vector<crypto::public_key>& additional_pub_keys);

View File

@ -35,8 +35,6 @@
#include "serialization/variant.h"
#include "crypto/crypto.h"
#include <boost/variant.hpp>
#define TX_EXTRA_PADDING_MAX_COUNT 255
#define TX_EXTRA_NONCE_MAX_COUNT 255
@ -55,6 +53,7 @@
#define TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK 0x77
#define TX_EXTRA_TAG_SERVICE_NODE_STATE_CHANGE 0x78
#define TX_EXTRA_TAG_BURN 0x79
#define TX_EXTRA_TAG_LOKI_NAME_SYSTEM 0x80
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
@ -381,6 +380,23 @@ namespace cryptonote
END_SERIALIZE()
};
struct tx_extra_loki_name_system
{
crypto::ed25519_public_key owner;
uint16_t type;
std::string name;
std::string value;
crypto::ed25519_signature signature;
crypto::hash make_signature_hash() const;
BEGIN_SERIALIZE()
FIELD(owner);
FIELD(type);
FIELD(name);
FIELD(value);
FIELD(signature);
END_SERIALIZE()
};
// tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
// varint tag;
@ -401,7 +417,8 @@ namespace cryptonote
tx_extra_tx_secret_key,
tx_extra_tx_key_image_proofs,
tx_extra_tx_key_image_unlock,
tx_extra_burn
tx_extra_burn,
tx_extra_loki_name_system
> tx_extra_field;
}
@ -424,3 +441,4 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_secret_key, TX
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_proofs, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_unlock, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_burn, TX_EXTRA_TAG_BURN);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_loki_name_system, TX_EXTRA_TAG_LOKI_NAME_SYSTEM);

View File

@ -42,6 +42,7 @@ set(cryptonote_core_sources
service_node_quorum_cop.cpp
service_node_swarm.cpp
tx_blink.cpp
loki_name_system_db.cpp
tx_pool.cpp
tx_sanity_check.cpp
miner.cpp
@ -55,6 +56,7 @@ set(cryptonote_core_private_headers
service_node_list.h
service_node_quorum_cop.h
service_node_swarm.h
loki_name_system_db.h
cryptonote_core.h
service_node_voting.h
tx_blink.h
@ -71,6 +73,7 @@ loki_add_library(cryptonote_core
${cryptonote_core_private_headers})
target_link_libraries(cryptonote_core
PUBLIC
sqlite
version
common
cncrypto

View File

@ -291,7 +291,7 @@ uint64_t Blockchain::get_current_blockchain_height() const
//------------------------------------------------------------------
//FIXME: possibly move this into the constructor, to avoid accidentally
// dereferencing a null BlockchainDB pointer
bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty, const GetCheckpointsCallback& get_checkpoints/* = nullptr*/)
bool Blockchain::init(BlockchainDB* db, sqlite3 *lns_db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty, const GetCheckpointsCallback& get_checkpoints/* = nullptr*/)
{
LOG_PRINT_L3("Blockchain::" << __func__);
@ -463,6 +463,14 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
return false;
}
uint64_t tail_height = 0;
crypto::hash tail_hash = get_tail_id(tail_height);
if (!m_lns_db.init(lns_db, tail_height, tail_hash))
{
MERROR("LNS failed to initialise");
return false;
}
hook_block_added(m_checkpoints);
hook_blockchain_detached(m_checkpoints);
for (InitHook* hook : m_init_hooks)
@ -471,11 +479,11 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
return true;
}
//------------------------------------------------------------------
bool Blockchain::init(BlockchainDB* db, HardFork*& hf, const network_type nettype, bool offline)
bool Blockchain::init(BlockchainDB* db, HardFork*& hf, sqlite3 *lns_db, const network_type nettype, bool offline)
{
if (hf != nullptr)
m_hardfork = hf;
bool res = init(db, nettype, offline, NULL);
bool res = init(db, lns_db, nettype, offline, NULL);
if (hf == nullptr)
hf = m_hardfork;
return res;
@ -3225,6 +3233,22 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
}
if (tx.type == txtype::loki_name_system)
{
cryptonote::tx_extra_loki_name_system data;
if (!cryptonote::get_loki_name_system_from_tx_extra(tx.extra, data))
{
MERROR_VER("TX: " << tx.type << " " << get_transaction_hash(tx) << ", didn't have loki name service in the tx_extra");
return false;
}
if (!lns::validate_lns_entry(tx, data))
{
MERROR_VER("TX: " << tx.type << " " << get_transaction_hash(tx) << ", owner = " << data.owner << ", type = " << (int)data.type << ", name = " << data.name);
return false;
}
}
}
else
{
@ -4045,6 +4069,48 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
}
}
checkpoint_t immutable_checkpoint = {};
if (bl.major_version >= cryptonote::network_version_14_blink_lns &&
m_db->get_immutable_checkpoint(&immutable_checkpoint, blockchain_height))
{
static uint64_t hf14_height = m_hardfork->get_earliest_ideal_height_for_version(network_version_14_blink_lns);
uint64_t start_height = std::max(m_lns_db.height(), hf14_height);
int64_t total_blocks = static_cast<int64_t>(immutable_checkpoint.height) - static_cast<int64_t>(start_height);
while (total_blocks > 0)
{
int64_t constexpr BLOCK_COUNT = 1000;
int64_t num_blocks = (total_blocks < BLOCK_COUNT) ? total_blocks : BLOCK_COUNT;
total_blocks -= num_blocks;
std::vector<std::pair<cryptonote::blobdata, cryptonote::block>> blocks;
if (!get_blocks(start_height, static_cast<uint64_t>(num_blocks), blocks))
{
LOG_ERROR("Unable to get checkpointed historical blocks for updating LNS DB");
pop_block_from_blockchain();
return false;
}
for (std::pair<cryptonote::blobdata, cryptonote::block> const &pair : blocks)
{
std::vector<cryptonote::transaction> old_txs;
std::vector<crypto::hash> old_missed_txs;
if (!get_transactions(pair.second.tx_hashes, old_txs, old_missed_txs))
{
MERROR("Unable to get transactions for block for updating LNS DB: " << cryptonote::get_block_hash(pair.second));
pop_block_from_blockchain();
return false;
}
if (!m_lns_db.add_block(nettype(), pair.second, old_txs))
{
MERROR("Unable to process block for updating LNS DB: " << cryptonote::get_block_hash(pair.second));
return false;
}
}
}
}
TIME_MEASURE_FINISH(addblock);
// TODO(loki): Temporary forking code.

View File

@ -57,7 +57,9 @@
#include "checkpoints/checkpoints.h"
#include "cryptonote_basic/hardfork.h"
#include "blockchain_db/blockchain_db.h"
#include "cryptonote_core/loki_name_system_db.h"
struct sqlite3;
namespace service_nodes { class service_node_list; };
namespace tools { class Notify; }
@ -140,7 +142,7 @@ namespace cryptonote
*
* @return true on success, false if any initialization steps fail
*/
bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0, const GetCheckpointsCallback& get_checkpoints = nullptr);
bool init(BlockchainDB* db, sqlite3 *lns_db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0, const GetCheckpointsCallback& get_checkpoints = nullptr);
/**
* @brief Initialize the Blockchain state
@ -152,7 +154,7 @@ namespace cryptonote
*
* @return true on success, false if any initialization steps fail
*/
bool init(BlockchainDB* db, HardFork*& hf, const network_type nettype = MAINNET, bool offline = false);
bool init(BlockchainDB* db, HardFork*& hf, sqlite3 *lns_db, const network_type nettype = MAINNET, bool offline = false);
/**
* @brief Uninitializes the blockchain state
@ -1051,6 +1053,8 @@ namespace cryptonote
*/
bool blink_rollback(uint64_t rollback_height);
lns::name_system_db const &name_system_db() { return m_lns_db; }
#ifndef IN_UNIT_TESTS
private:
#endif
@ -1067,6 +1071,7 @@ namespace cryptonote
tx_memory_pool& m_tx_pool;
service_nodes::service_node_list& m_service_node_list;
lns::name_system_db m_lns_db;
mutable boost::recursive_mutex m_blockchain_lock; // TODO: add here reader/writer lock

View File

@ -67,6 +67,7 @@ extern "C" {
#include "common/i18n.h"
#include "net/local_ip.h"
#include "cryptonote_protocol/quorumnet.h"
#include "sqlite/sqlite3.h"
#include "common/loki_integration_test_hooks.h"
@ -684,17 +685,19 @@ namespace cryptonote
bool sync_on_blocks = true;
uint64_t sync_threshold = 1;
std::string const lns_db_file_path = m_config_folder + "/lns.db";
#if !defined(LOKI_ENABLE_INTEGRATION_TEST_HOOKS) // In integration mode, don't delete the DB. This should be explicitly done in the tests. Otherwise the more likely behaviour is persisting the DB across multiple daemons in the same test.
if (m_nettype == FAKECHAIN)
{
#if !defined(LOKI_ENABLE_INTEGRATION_TEST_HOOKS) // In integration mode, don't delete the DB. This should be explicitly done in the tests. Otherwise the more likely behaviour is persisting the DB across multiple daemons in the same test.
// reset the db by removing the database file before opening it
if (!db->remove_data_file(filename))
{
MERROR("Failed to remove data file in " << filename);
return false;
}
#endif
boost::filesystem::remove(lns_db_file_path);
}
#endif
try
{
@ -850,9 +853,11 @@ namespace cryptonote
m_checkpoints_path = checkpoint_json_hashfile_fullpath.string();
}
const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty);
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty, get_checkpoints);
sqlite3 *lns_db = lns::init_loki_name_system(lns_db_file_path.c_str());
if (!lns_db) return false;
const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty);
r = m_blockchain_storage.init(db.release(), lns_db, m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty, get_checkpoints);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
if (!command_line::is_arg_defaulted(vm, arg_recalculate_difficulty))

View File

@ -479,7 +479,7 @@ namespace cryptonote
tx.extra = extra;
crypto::public_key txkey_pub;
if (tx.type == txtype::stake)
if (tx.type == txtype::stake || tx.type == txtype::loki_name_system)
add_tx_secret_key_to_tx_extra(tx.extra, tx_key);
// if we have a stealth payment id, find it and encrypt it with the tx key now

View File

@ -0,0 +1,558 @@
#include "loki_name_system_db.h"
#include "checkpoints/checkpoints.h"
#include "common/loki.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "cryptonote_basic/tx_extra.h"
#include "sqlite/sqlite3.h"
extern "C"
{
#include "sodium.h"
}
namespace lns
{
enum struct lns_sql_type {
save_user,
save_setting,
save_mapping,
get_sentinel_start,
get_user,
get_setting,
get_mapping,
get_sentinel_end,
};
constexpr char DROP_TABLE_SQL[] = R"FOO(
DROP TABLE IF EXISTS "user";
DROP TABLE IF EXISTS "settings";
DROP TABLE IF EXISTS "mappings";
)FOO";
constexpr char BUILD_TABLE_SQL[] = R"FOO(
CREATE TABLE IF NOT EXISTS "user"(
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"public_key" BLOB NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS "settings" (
"top_height" INTEGER NOT NULL,
"top_hash" VARCHAR NOT NULL,
"version" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "mappings" (
"id" INTEGER PRIMARY KEY NOT NULL,
"type" INTEGER NOT NULL,
"name" VARCHAR NOT NULL,
"value" BLOB NOT NULL,
"register_height" INTEGER NOT NULL,
"user_id" INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES user (id)
);
CREATE UNIQUE INDEX "name_type_id" ON mappings(name, type);
)FOO";
enum lns_db_setting_row
{
lns_db_setting_row_id,
lns_db_setting_row_top_height,
lns_db_setting_row_top_hash,
lns_db_setting_row_version,
};
char constexpr SAVE_SETTINGS_CMD[] =R"FOO(
INSERT OR REPLACE INTO settings
(rowid, top_height, top_hash, version)
VALUES (1,?,?,?);
)FOO";
char constexpr GET_SETTINGS_CMD[] = R"FOO(
SELECT * FROM settings WHERE "id" = 0
)FOO";
enum user_record_row
{
user_record_row_id,
user_record_row_public_key,
};
char constexpr SAVE_USER_CMD[] = "INSERT INTO user (public_key) VALUES (?);";
char constexpr GET_USER_BY_KEY_CMD[] = R"FOO(
SELECT * FROM user WHERE "public_key" = ?
)FOO";
char constexpr GET_USER_BY_ID_CMD[] = R"FOO(
SELECT * FROM user WHERE "id" = ?
)FOO";
enum mapping_record_row
{
mapping_record_row_id,
mapping_record_row_type,
mapping_record_row_name,
mapping_record_row_value,
mapping_record_row_register_height,
mapping_record_row_user_id,
};
char constexpr GET_MAPPING_CMD[] = R"FOO(
SELECT * FROM mappings WHERE "type" = ? AND "value" = ?
)FOO";
char constexpr SAVE_MAPPING_CMD[] =
"INSERT INTO mappings "
"(type, name, value, register_height, user_id)"
"VALUES (?,?,?,?,?);";
static void 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));
}
static bool sql_run_statement(lns_sql_type type, sqlite3_stmt *statement, void *context)
{
bool data_loaded = false;
bool result = false;
for (bool infinite_loop = true; infinite_loop;)
{
int step_result = sqlite3_step(statement);
switch (step_result)
{
case SQLITE_ROW:
{
switch (type)
{
default:
{
MERROR("Unhandled lns type enum with value: " << (int)type << ", in: " << __func__);
}
break;
case lns_sql_type::get_user:
{
auto *entry = reinterpret_cast<user_record *>(context);
entry->id = sqlite3_column_int(statement, user_record_row_id);
sql_copy_blob(statement, user_record_row_public_key, entry->key.data, sizeof(entry->key.data));
data_loaded = true;
}
break;
case lns_sql_type::get_setting:
{
auto *entry = reinterpret_cast<settings_record *>(context);
entry->top_height = static_cast<uint64_t>(sqlite3_column_int64(statement, lns_db_setting_row_top_height));
sql_copy_blob(statement, lns_db_setting_row_top_hash, entry->top_hash.data, sizeof(entry->top_hash.data));
entry->version = sqlite3_column_int(statement, lns_db_setting_row_version);
data_loaded = true;
}
break;
case lns_sql_type::get_mapping:
{
auto *entry = reinterpret_cast<mapping_record *>(context);
entry->type = static_cast<uint16_t>(sqlite3_column_int(statement, mapping_record_row_type));
entry->register_height = static_cast<uint16_t>(sqlite3_column_int(statement, mapping_record_row_register_height));
entry->user_id = sqlite3_column_int(statement, mapping_record_row_user_id);
int name_len = sqlite3_column_bytes(statement, mapping_record_row_name);
int value_len = sqlite3_column_bytes(statement, mapping_record_row_value);
auto *value = reinterpret_cast<char const *>(sqlite3_column_text(statement, mapping_record_row_value));
if (validate_lns_name_value_mapping_lengths(entry->type, name_len, value, value_len))
{
auto *name = reinterpret_cast<char const *>(sqlite3_column_text(statement, mapping_record_row_name));
entry->name = std::string(name, name_len);
entry->value = std::string(value, value_len);
data_loaded = true;
}
}
break;
}
}
break;
case SQLITE_BUSY: break;
case SQLITE_DONE:
{
infinite_loop = false;
result = (type > lns_sql_type::get_sentinel_start && type < lns_sql_type::get_sentinel_end) ? data_loaded : true;
break;
}
default:
{
LOG_PRINT_L1("Failed to execute statement: " << sqlite3_sql(statement) <<", reason: " << sqlite3_errstr(step_result));
infinite_loop = false;
break;
}
}
}
sqlite3_reset(statement);
sqlite3_clear_bindings(statement);
return result;
}
static bool sql_compile_statement(sqlite3 *db, char const *query, int query_len, sqlite3_stmt **statement)
{
int prepare_result = sqlite3_prepare_v2(db, query, query_len, statement, nullptr);
bool result = prepare_result == SQLITE_OK;
if (!result) MERROR("Can not compile SQL statement: " << query << ", reason: " << sqlite3_errstr(prepare_result));
return result;
}
sqlite3 *init_loki_name_system(char const *file_path)
{
sqlite3 *result = nullptr;
int sql_init = sqlite3_initialize();
if (sql_init != SQLITE_OK)
{
MERROR("Failed to initialize sqlite3: " << sqlite3_errstr(sql_init));
return nullptr;
}
int sql_open = sqlite3_open(file_path, &result);
if (sql_open != SQLITE_OK)
{
MERROR("Failed to open LNS db at: " << file_path << ", reason: " << sqlite3_errstr(sql_init));
return nullptr;
}
return result;
}
bool validate_lns_name_value_mapping_lengths(uint16_t type, int name_len, char const *value, int value_len)
{
int max_name_len = lns::GENERIC_NAME_MAX;
int max_value_len = lns::GENERIC_VALUE_MAX;
bool value_require_exact_len = true;
if (type == static_cast<uint16_t>(mapping_type::blockchain))
{
max_name_len = BLOCKCHAIN_NAME_MAX;
max_value_len = BLOCKCHAIN_WALLET_ADDRESS_LENGTH;
}
else if (type == static_cast<uint16_t>(mapping_type::lokinet))
{
max_name_len = LOKINET_DOMAIN_NAME_MAX;
max_value_len = LOKINET_ADDRESS_LENGTH;
}
else if (type == static_cast<uint16_t>(mapping_type::messenger))
{
max_name_len = MESSENGER_DISPLAY_NAME_MAX;
max_value_len = MESSENGER_PUBLIC_KEY_LENGTH;
}
else
{
value_require_exact_len = false;
}
if (name_len > max_name_len || name_len == 0)
return false;
if (value_require_exact_len)
{
if (value_len != max_value_len)
return false;
}
else
{
if (value_len > max_value_len || value_len == 0)
return false;
}
// NOTE: Messenger public keys are 33 bytes, with the first byte being 0x05 and the remaining 32 being the public key.
if (type == static_cast<uint16_t>(mapping_type::messenger))
{
if (value[0] != 0x05)
return false;
}
return true;
}
bool validate_lns_entry(cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system const &entry)
{
if (!validate_lns_name_value_mapping_lengths(entry.type, static_cast<int>(entry.name.size()), entry.value.data(), static_cast<int>(entry.value.size())))
{
LOG_PRINT_L1("LNS TX " << cryptonote::get_transaction_hash(tx) << " Failed name: " << entry.name << "or value: " << entry.value << " validation");
return false;
}
// TODO: Validate burn amount in the tx_extra
crypto::hash hash = entry.make_signature_hash();
if (crypto_sign_ed25519_verify_detached(entry.signature.data, reinterpret_cast<const unsigned char *>(hash.data), sizeof(hash.data), entry.owner.data) != 0)
{
LOG_PRINT_L1("LNS TX " << cryptonote::get_transaction_hash(tx) << " Failed signature validation");
return false;
}
return true;
}
static bool build_default_tables(sqlite3 *db)
{
char *table_err_msg = nullptr;
int table_created = sqlite3_exec(db, BUILD_TABLE_SQL, nullptr /*callback*/, nullptr /*callback context*/, &table_err_msg);
if (table_created != SQLITE_OK)
{
MERROR("Can not generate SQL table for LNS: " << (table_err_msg ? table_err_msg : "??"));
sqlite3_free(table_err_msg);
return false;
}
return true;
}
enum struct db_version : int { v1, };
auto constexpr DB_VERSION = db_version::v1;
bool name_system_db::init(sqlite3 *db, uint64_t top_height, crypto::hash const &top_hash)
{
if (!db) return false;
this->db = db;
if (!build_default_tables(db))
return false;
if (!sql_compile_statement(db, SAVE_USER_CMD, loki::array_count(SAVE_USER_CMD), &save_user_cmd) ||
!sql_compile_statement(db, SAVE_MAPPING_CMD, loki::array_count(SAVE_MAPPING_CMD), &save_mapping_cmd) ||
!sql_compile_statement(db, SAVE_SETTINGS_CMD, loki::array_count(SAVE_SETTINGS_CMD), &save_settings_cmd) ||
!sql_compile_statement(db, GET_USER_BY_KEY_CMD, loki::array_count(GET_USER_BY_KEY_CMD), &get_user_by_key_cmd) ||
!sql_compile_statement(db, GET_USER_BY_ID_CMD, loki::array_count(GET_USER_BY_ID_CMD), &get_user_by_id_cmd) ||
!sql_compile_statement(db, GET_MAPPING_CMD, loki::array_count(GET_MAPPING_CMD), &get_mapping_cmd) ||
!sql_compile_statement(db, GET_SETTINGS_CMD, loki::array_count(GET_SETTINGS_CMD), &get_settings_cmd)
)
{
return false;
}
if (settings_record settings = get_settings())
{
if (settings.top_height == top_height && settings.top_hash == top_hash)
{
this->last_processed_height = settings.top_height;
assert(settings.version == static_cast<int>(DB_VERSION));
}
else
{
sqlite3_exec(db, DROP_TABLE_SQL, nullptr /*callback*/, nullptr /*callback context*/, nullptr);
if (!build_default_tables(db)) return false;
}
}
return true;
}
static bool process_loki_name_system_tx(cryptonote::network_type nettype,
uint64_t block_height,
const cryptonote::transaction &tx,
cryptonote::tx_extra_loki_name_system &tx_extra)
{
if (!cryptonote::get_loki_name_system_from_tx_extra(tx.extra, tx_extra))
{
LOG_PRINT_L1("TX: " << tx.type << " " << get_transaction_hash(tx) << ", didn't have loki name service in the tx_extra");
return false;
}
if (!validate_lns_entry(tx, tx_extra))
{
assert("Failed to validate acquire name service. Should already have failed validation prior" == nullptr);
LOG_PRINT_L1("LNS TX: Failed to validate for tx: " << get_transaction_hash(tx) << ". This should have failed validation earlier");
return false;
}
return true;
}
enum struct sql_transaction_type
{
begin,
commit,
rollback,
count,
};
static bool sql_transaction(sqlite3 *db, sql_transaction_type type)
{
char *sql_err = nullptr;
char const *const CMDS[] = {
"BEGIN;",
"END;",
"ROLLBACK;",
};
static_assert(loki::array_count(CMDS) == static_cast<int>(sql_transaction_type::count), "Unexpected enum to string mismatch");
if (sqlite3_exec(db, CMDS[static_cast<int>(type)], NULL, NULL, &sql_err) != SQLITE_OK)
{
MERROR("Can not execute transactional step: " << CMDS[static_cast<int>(type)] << ", reason: " << (sql_err ? sql_err : "??"));
sqlite3_free(sql_err);
return false;
}
return true;
}
bool name_system_db::add_block(cryptonote::network_type nettype,
const cryptonote::block &block,
const std::vector<cryptonote::transaction> &txs)
{
uint64_t height = cryptonote::get_block_height(block);
if (block.major_version >= cryptonote::network_version_14_blink_lns)
{
for (cryptonote::transaction const &tx : txs)
{
if (tx.type != cryptonote::txtype::loki_name_system)
continue;
cryptonote::tx_extra_loki_name_system entry = {};
if (!process_loki_name_system_tx(nettype, height, tx, entry))
continue;
bool transaction_begun = false;
int64_t user_id = 0;
if (user_record user = get_user_by_key(entry.owner)) user_id = user.id;
if (user_id == 0)
{
transaction_begun = sql_transaction(db, sql_transaction_type::begin);
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);
if (transaction_begun && !sql_transaction(db, sql_transaction_type::rollback))
{
MERROR("Failed to rollback transaction in LNS DB");
return false;
}
continue;
}
}
assert(user_id != 0);
if (!transaction_begun)
transaction_begun = sql_transaction(db, sql_transaction_type::begin);
if (save_mapping(static_cast<uint16_t>(entry.type), entry.name, entry.value.data(), entry.value.size(), height, user_id))
{
if (transaction_begun && !sql_transaction(db, sql_transaction_type::commit))
{
MERROR("Failed to commit user and or mapping transaction to LNS DB");
return false;
}
}
else
{
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);
if (transaction_begun && !sql_transaction(db, sql_transaction_type::rollback))
{
MERROR("Failed to rollback transaction in LNS DB");
return false;
}
}
}
}
last_processed_height = height;
save_settings(height, cryptonote::get_block_hash(block), static_cast<int>(DB_VERSION));
return true;
}
bool name_system_db::save_user(crypto::ed25519_public_key const &key, int64_t *row_id)
{
sqlite3_stmt *statement = save_user_cmd;
sqlite3_clear_bindings(statement);
sqlite3_bind_blob(statement, 1 /*sql param index*/, &key, sizeof(key), nullptr /*destructor*/);
bool result = sql_run_statement(lns_sql_type::save_user, statement, nullptr);
if (row_id) *row_id = sqlite3_last_insert_rowid(db);
return result;
}
bool name_system_db::save_mapping(uint16_t type,
std::string const &name,
void const *value,
int value_len,
uint64_t register_height,
int64_t user_id)
{
sqlite3_stmt *statement = save_mapping_cmd;
sqlite3_bind_int (statement, mapping_record_row_type, type);
sqlite3_bind_text (statement, mapping_record_row_name, name.c_str(), name.size(), nullptr /*destructor*/);
sqlite3_bind_blob (statement, mapping_record_row_value, value, value_len, nullptr /*destructor*/);
sqlite3_bind_int64(statement, mapping_record_row_register_height, static_cast<int64_t>(register_height));
sqlite3_bind_int64(statement, mapping_record_row_user_id, user_id);
bool result = sql_run_statement(lns_sql_type::save_mapping, statement, nullptr);
return result;
}
bool name_system_db::save_settings(uint64_t top_height, crypto::hash const &top_hash, int version)
{
sqlite3_stmt *statement = save_settings_cmd;
sqlite3_bind_blob (statement, lns_db_setting_row_top_hash, top_hash.data, sizeof(top_hash), nullptr /*destructor*/);
sqlite3_bind_int64(statement, lns_db_setting_row_top_height, top_height);
sqlite3_bind_int (statement, lns_db_setting_row_version, version);
bool result = sql_run_statement(lns_sql_type::save_setting, statement, nullptr);
return result;
}
user_record name_system_db::get_user_by_key(crypto::ed25519_public_key const &key) const
{
sqlite3_stmt *statement = get_user_by_key_cmd;
sqlite3_clear_bindings(statement);
sqlite3_bind_blob(statement, 1 /*sql param index*/, &key, sizeof(key), nullptr /*destructor*/);
user_record result = {};
result.loaded = sql_run_statement(lns_sql_type::get_user, statement, &result);
return result;
}
user_record name_system_db::get_user_by_id(int user_id) const
{
sqlite3_stmt *statement = get_user_by_id_cmd;
sqlite3_clear_bindings(statement);
sqlite3_bind_int(statement, 1 /*sql param index*/, user_id);
user_record result = {};
result.loaded = sql_run_statement(lns_sql_type::get_user, statement, &result);
return result;
}
mapping_record name_system_db::get_mapping(uint16_t type, void const *value, size_t value_len) const
{
sqlite3_stmt *statement = get_mapping_cmd;
sqlite3_clear_bindings(statement);
sqlite3_bind_int(statement, 1 /*sql param index*/, type);
sqlite3_bind_blob(statement, 2 /*sql param index*/, value, value_len, nullptr /*destructor*/);
mapping_record result = {};
result.loaded = sql_run_statement(lns_sql_type::get_mapping, statement, &result);
return result;
}
mapping_record name_system_db::get_mapping(uint16_t type, std::string const &value) const
{
mapping_record result = get_mapping(type, value.data(), value.size());
return result;
}
settings_record name_system_db::get_settings() const
{
sqlite3_stmt *statement = get_user_by_id_cmd;
settings_record result = {};
result.loaded = sql_run_statement(lns_sql_type::get_setting, statement, &result);
return result;
}
}; // namespace service_nodes

View File

@ -0,0 +1,106 @@
#ifndef LOKI_NAME_SYSTEM_DB_H
#define LOKI_NAME_SYSTEM_DB_H
#include "crypto/crypto.h"
#include "cryptonote_config.h"
#include <string>
struct sqlite3;
struct sqlite3_stmt;
namespace cryptonote
{
struct checkpoint_t;
struct block;
struct transaction;
struct tx_extra_loki_name_system;
struct account_address;
}; // namespace cryptonote
namespace lns
{
constexpr uint64_t BURN_REQUIREMENT = 100 * COIN;
constexpr uint64_t BLOCKCHAIN_NAME_MAX = 95;
constexpr uint64_t BLOCKCHAIN_WALLET_ADDRESS_LENGTH = 69;
constexpr uint64_t LOKINET_DOMAIN_NAME_MAX = 253;
constexpr uint64_t LOKINET_ADDRESS_LENGTH = 32;
constexpr uint64_t LOKINET_NAME_LIFETIME = BLOCKS_EXPECTED_IN_YEARS(1) + BLOCKS_EXPECTED_IN_DAYS(31);
constexpr uint64_t MESSENGER_DISPLAY_NAME_MAX = 30;
constexpr uint64_t MESSENGER_PUBLIC_KEY_LENGTH = 33;
constexpr uint64_t GENERIC_NAME_MAX = 255;
constexpr uint64_t GENERIC_VALUE_MAX = 255;
sqlite3 *init_loki_name_system(char const *file_path);
bool validate_lns_name_value_mapping_lengths(uint16_t type, int name_len, char const *value, int value_len);
bool validate_lns_entry(cryptonote::transaction const &tx, cryptonote::tx_extra_loki_name_system const &entry);
struct user_record
{
operator bool() const { return loaded; }
bool loaded;
int64_t id;
crypto::ed25519_public_key key;
};
struct settings_record
{
operator bool() const { return loaded; }
bool loaded;
uint64_t top_height;
crypto::hash top_hash;
int version;
};
enum struct mapping_type : uint16_t
{
blockchain,
lokinet,
messenger,
};
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;
};
struct name_system_db
{
sqlite3 *db = nullptr;
sqlite3_stmt *save_user_cmd = nullptr;
sqlite3_stmt *save_mapping_cmd = nullptr;
sqlite3_stmt *save_settings_cmd = nullptr;
sqlite3_stmt *get_user_by_key_cmd = nullptr;
sqlite3_stmt *get_user_by_id_cmd = nullptr;
sqlite3_stmt *get_mapping_cmd = nullptr;
sqlite3_stmt *get_settings_cmd = nullptr;
bool init (sqlite3 *db, uint64_t top_height, crypto::hash const &top_hash);
bool add_block (cryptonote::network_type nettype, const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs);
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, void const *value, int value_len, uint64_t register_height, int64_t user_id);
bool save_settings (uint64_t top_height, crypto::hash const &top_hash, int version);
user_record get_user_by_key(crypto::ed25519_public_key const &key) const;
user_record get_user_by_id (int user_id) const;
mapping_record get_mapping (uint16_t type, void const *value, size_t value_len) const;
mapping_record get_mapping (uint16_t type, std::string const &value) const;
settings_record get_settings () const;
private:
uint64_t last_processed_height = 0;
};
}; // namespace service_nodes
#endif // LOKI_NAME_SYSTEM_DB_H

View File

@ -408,7 +408,7 @@ namespace service_nodes
std::vector<service_node_info::contribution_t> locked_contributions;
};
static uint64_t get_reg_tx_staking_output_contribution(const cryptonote::transaction& tx, int i, crypto::key_derivation const &derivation, hw::device& hwdev)
static uint64_t get_tx_output_amount(const cryptonote::transaction& tx, int i, crypto::key_derivation const &derivation, hw::device& hwdev)
{
if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
{
@ -720,7 +720,7 @@ namespace service_nodes
if (!cryptonote::get_tx_secret_key_from_tx_extra(tx.extra, parsed_contribution.tx_key))
{
LOG_PRINT_L1("Contribution TX: There was a service node contributor but no secret key in the tx extra on height: " << block_height << " for tx: " << get_transaction_hash(tx));
LOG_PRINT_L1("TX: There was a service node contributor but no secret key in the tx extra on height: " << block_height << " for tx: " << get_transaction_hash(tx));
return false;
}
@ -741,7 +741,7 @@ namespace service_nodes
crypto::key_derivation derivation;
if (!crypto::generate_key_derivation(parsed_contribution.address.m_view_public_key, parsed_contribution.tx_key, derivation))
{
LOG_PRINT_L1("Contribution TX: Failed to generate key derivation on height: " << block_height << " for tx: " << get_transaction_hash(tx));
LOG_PRINT_L1("TX: Failed to generate key derivation on height: " << block_height << " for tx: " << get_transaction_hash(tx));
return false;
}
@ -764,13 +764,13 @@ namespace service_nodes
cryptonote::tx_extra_tx_key_image_proofs key_image_proofs;
if (!get_tx_key_image_proofs_from_tx_extra(tx.extra, key_image_proofs))
{
LOG_PRINT_L1("Contribution TX: Didn't have key image proofs in the tx_extra, rejected on height: " << block_height << " for tx: " << get_transaction_hash(tx));
LOG_PRINT_L1("TX: Didn't have key image proofs in the tx_extra, rejected on height: " << block_height << " for tx: " << get_transaction_hash(tx));
return false;
}
for (size_t output_index = 0; output_index < tx.vout.size(); ++output_index)
{
uint64_t transferred = get_reg_tx_staking_output_contribution(tx, output_index, derivation, hwdev);
uint64_t transferred = get_tx_output_amount(tx, output_index, derivation, hwdev);
if (transferred == 0)
continue;
@ -793,7 +793,7 @@ namespace service_nodes
// P' := Derivation + B
if (!hwdev.derive_public_key(derivation, output_index, parsed_contribution.address.m_spend_public_key, ephemeral_pub_key))
{
LOG_PRINT_L1("Contribution TX: Could not derive TX ephemeral key on height: " << block_height << " for tx: " << get_transaction_hash(tx) << " for output: " << output_index);
LOG_PRINT_L1("TX: Could not derive TX ephemeral key on height: " << block_height << " for tx: " << get_transaction_hash(tx) << " for output: " << output_index);
continue;
}
@ -801,7 +801,7 @@ namespace service_nodes
const auto& out_to_key = boost::get<cryptonote::txout_to_key>(tx.vout[output_index].target);
if (out_to_key.key != ephemeral_pub_key)
{
LOG_PRINT_L1("Contribution TX: Derived TX ephemeral key did not match tx stored key on height: " << block_height << " for tx: " << get_transaction_hash(tx) << " for output: " << output_index);
LOG_PRINT_L1("TX: Derived TX ephemeral key did not match tx stored key on height: " << block_height << " for tx: " << get_transaction_hash(tx) << " for output: " << output_index);
continue;
}
}
@ -853,7 +853,7 @@ namespace service_nodes
}
if (has_correct_unlock_time)
parsed_contribution.transferred += get_reg_tx_staking_output_contribution(tx, i, derivation, hwdev);
parsed_contribution.transferred += get_tx_output_amount(tx, i, derivation, hwdev);
}
}
@ -1078,14 +1078,14 @@ namespace service_nodes
parsed_tx_contribution parsed_contribution = {};
if (!get_contribution(nettype, hf_version, tx, block_height, parsed_contribution))
{
LOG_PRINT_L1("Contribution TX: Could not decode contribution for service node: " << pubkey << " on height: " << block_height << " for tx: " << cryptonote::get_transaction_hash(tx));
LOG_PRINT_L1("TX: Could not decode contribution for service node: " << pubkey << " on height: " << block_height << " for tx: " << cryptonote::get_transaction_hash(tx));
return false;
}
auto iter = service_nodes_infos.find(pubkey);
if (iter == service_nodes_infos.end())
{
LOG_PRINT_L1("Contribution TX: Contribution received for service node: " << pubkey <<
LOG_PRINT_L1("TX: Contribution received for service node: " << pubkey <<
", but could not be found in the service node list on height: " << block_height <<
" for tx: " << cryptonote::get_transaction_hash(tx )<< "\n"
"This could mean that the service node was deregistered before the contribution was processed.");
@ -1095,7 +1095,7 @@ namespace service_nodes
const service_node_info& curinfo = *iter->second;
if (curinfo.is_fully_funded())
{
LOG_PRINT_L1("Contribution TX: Service node: " << pubkey <<
LOG_PRINT_L1("TX: Service node: " << pubkey <<
" is already fully funded, but contribution received on height: " << block_height <<
" for tx: " << cryptonote::get_transaction_hash(tx));
return false;
@ -1103,7 +1103,7 @@ namespace service_nodes
if (!cryptonote::get_tx_secret_key_from_tx_extra(tx.extra, parsed_contribution.tx_key))
{
LOG_PRINT_L1("Contribution TX: Failed to get tx secret key from contribution received on height: " << block_height << " for tx: " << cryptonote::get_transaction_hash(tx));
LOG_PRINT_L1("TX: Failed to get tx secret key from contribution received on height: " << block_height << " for tx: " << cryptonote::get_transaction_hash(tx));
return false;
}
@ -1129,7 +1129,7 @@ namespace service_nodes
if (too_many_contributions)
{
LOG_PRINT_L1("Contribution TX: Already hit the max number of contributions: " << MAX_NUMBER_OF_CONTRIBUTORS <<
LOG_PRINT_L1("TX: Already hit the max number of contributions: " << MAX_NUMBER_OF_CONTRIBUTORS <<
" for contributor: " << cryptonote::get_account_address_as_str(nettype, false, parsed_contribution.address) <<
" on height: " << block_height <<
" for tx: " << cryptonote::get_transaction_hash(tx));
@ -1146,7 +1146,7 @@ namespace service_nodes
if (parsed_contribution.transferred < min_contribution)
{
LOG_PRINT_L1("Contribution TX: Amount " << parsed_contribution.transferred <<
LOG_PRINT_L1("TX: Amount " << parsed_contribution.transferred <<
" did not meet min " << min_contribution <<
" for service node: " << pubkey <<
" on height: " << block_height <<
@ -1494,17 +1494,15 @@ namespace service_nodes
void service_node_list::process_block(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
{
uint64_t block_height = cryptonote::get_block_height(block);
uint8_t hf_version = m_blockchain.get_hard_fork_version(block_height);
uint8_t hf_version = block.major_version;
if (hf_version < 9)
return;
//
// Cull old history
//
uint64_t cull_height = short_term_state_cull_height(hf_version, block_height);
{
uint64_t cull_height = short_term_state_cull_height(hf_version, block_height);
auto end_it = m_transient.state_history.upper_bound(cull_height);
auto end_it = m_transient.state_history.upper_bound(cull_height);
for (auto it = m_transient.state_history.begin(); it != end_it; it++)
{
if (m_store_quorum_history)
@ -1525,6 +1523,7 @@ namespace service_nodes
}
m_transient.state_archive.emplace_hint(m_transient.state_archive.end(), std::move(*it));
}
}
m_transient.state_history.erase(m_transient.state_history.begin(), end_it);
@ -1532,21 +1531,12 @@ namespace service_nodes
m_transient.old_quorum_states.erase(m_transient.old_quorum_states.begin(), m_transient.old_quorum_states.begin() + (m_transient.old_quorum_states.size() - m_store_quorum_history));
}
//
// Cull alt state history
//
if (hf_version >= cryptonote::network_version_12_checkpointing && m_transient.alt_state.size())
for (auto it = m_transient.alt_state.begin(); it != m_transient.alt_state.end(); )
{
cryptonote::checkpoint_t immutable_checkpoint;
if (m_blockchain.get_db().get_immutable_checkpoint(&immutable_checkpoint, block_height))
{
for (auto it = m_transient.alt_state.begin(); it != m_transient.alt_state.end(); )
{
state_t const &alt_state = it->second;
if (alt_state.height < immutable_checkpoint.height) it = m_transient.alt_state.erase(it);
else it++;
}
}
state_t const &alt_state = it->second;
if (alt_state.height < cull_height) it = m_transient.alt_state.erase(it);
else it++;
}
cryptonote::network_type nettype = m_blockchain.nettype();

View File

@ -316,7 +316,6 @@ namespace service_nodes
bool validate_miner_tx(const crypto::hash& prev_id, const cryptonote::transaction& miner_tx, uint64_t height, int hard_fork_version, cryptonote::block_reward_parts const &base_reward) const override;
bool alt_block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const *checkpoint) override;
block_winner get_block_winner() const { std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex); return m_state.get_block_winner(); }
bool is_service_node(const crypto::public_key& pubkey, bool require_active = true) const;
bool is_key_image_locked(crypto::key_image const &check_image, uint64_t *unlock_height = nullptr, service_node_info::contribution_t *the_locked_contribution = nullptr) const;
@ -489,6 +488,7 @@ namespace service_nodes
const service_node_keys *my_keys);
bool process_key_image_unlock_tx(cryptonote::network_type nettype, uint64_t block_height, const cryptonote::transaction &tx);
block_winner get_block_winner() const;
};
// Can be set to true (via --dev-allow-local-ips) for debugging a new testnet on a local private network.

View File

@ -218,6 +218,36 @@ namespace cryptonote
}
}
else if (tx.type == txtype::loki_name_system)
{
tx_extra_loki_name_system data;
if (!cryptonote::get_loki_name_system_from_tx_extra(tx.extra, data))
{
MERROR("Could not get acquire name service from tx: " << get_transaction_hash(tx) << ", tx to add is possibly invalid, rejecting");
return true;
}
std::vector<transaction> pool_txs;
get_transactions(pool_txs);
for (const transaction& pool_tx : pool_txs)
{
if (pool_tx.type != tx.type)
continue;
tx_extra_loki_name_system pool_data;
if (!cryptonote::get_loki_name_system_from_tx_extra(pool_tx.extra, data))
{
LOG_PRINT_L1("Could not get acquire name service from tx: " << get_transaction_hash(tx) << ", possibly corrupt tx in the pool");
return true;
}
if (data.name == pool_data.name)
{
LOG_PRINT_L1("New TX: " << get_transaction_hash(tx) << ", has TX: " << get_transaction_hash(pool_tx) << " from the pool that is requesting to unlock the same key image already.");
return true;
}
}
}
else
{
// NOTE(loki): This is a developer error. If we come across this in production, be conservative and just reject

View File

@ -86,6 +86,7 @@ BLOB_SERIALIZER(crypto::key_derivation);
BLOB_SERIALIZER(crypto::key_image);
BLOB_SERIALIZER(crypto::signature);
BLOB_SERIALIZER(crypto::ed25519_public_key);
BLOB_SERIALIZER(crypto::ed25519_signature);
VARIANT_TAG(debug_archive, crypto::hash, "hash");
VARIANT_TAG(debug_archive, crypto::hash8, "hash8");
VARIANT_TAG(debug_archive, crypto::public_key, "public_key");

View File

@ -89,6 +89,7 @@ extern "C"
{
#include "crypto/keccak.h"
#include "crypto/crypto-ops.h"
#include <sodium.h>
}
using namespace std;

View File

@ -65,6 +65,7 @@
#include "node_rpc_proxy.h"
#include "message_store.h"
#include "wallet_light_rpc.h"
#include "cryptonote_core/loki_name_system_db.h"
#include "common/loki_integration_test_hooks.h"

View File

@ -121,7 +121,7 @@ private:
get_test_options(): hard_forks{{std::make_pair(cryptonote::network_version_7, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)LONG_TERM_BLOCK_WEIGHT_WINDOW)}} {} \
} opts; \
cryptonote::Blockchain *bc = &bc_objects.m_blockchain; \
bool r = bc->init(new TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0); \
bool r = bc->init(new TestDB(), nullptr /*lns_db*/, cryptonote::FAKECHAIN, true, &opts.test_options, 0); \
if (!r) \
{ \
fprintf(stderr, "Failed to init blockchain\n"); \

View File

@ -334,7 +334,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events
transaction tmp_tx;
if (!loki_tx_builder(events, tmp_tx, blk_0r, miner_account, miner_account, blk_0.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
if (!loki_tx_builder(events, tmp_tx, blk_0r, miner_account, miner_account.get_keys().m_account_address, blk_0.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_0r);
@ -361,7 +361,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry>
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
transaction tmp_tx;
if (!loki_tx_builder(events, tmp_tx, blk_1r, miner_account, miner_account, blk_1.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
if (!loki_tx_builder(events, tmp_tx, blk_1r, miner_account, miner_account.get_keys().m_account_address, blk_1.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_1);
@ -578,7 +578,7 @@ bool gen_block_invalid_binary_format::generate(std::vector<test_event_entry>& ev
gen.add_mined_money_unlock_blocks();
uint64_t last_valid_height = gen.height();
cryptonote::transaction tx = gen.create_and_add_tx(gen.first_miner_, gen.first_miner_, MK_COINS(30));
cryptonote::transaction tx = gen.create_and_add_tx(gen.first_miner_, gen.first_miner_.get_keys().m_account_address, MK_COINS(30));
loki_blockchain_entry entry = gen.create_next_block({tx});
serialized_block block(t_serializable_object_to_blob(entry.block));

View File

@ -49,31 +49,11 @@
#include "chaingen.h"
#include "device/device.hpp"
// TODO(loki): Improved register callback that all tests should start using.
// Classes are not regenerated when replaying the test through the blockchain.
// Before, state saved in this class like saving indexes where events ocurred
// would not persist because when replaying tests we create a new instance of
// the test class.
extern "C"
{
#include <sodium.h>
}
// i.e.
#if 0
std::vector<events> events;
{
gen_service_nodes generator;
generator.generate(events);
}
gen_service_nodes generator;
replay_events_through_core(generator, ...)
#endif
// Which is stupid. Instead we preserve the original generator. This means
// all the tests that use callbacks to preserve state can be removed.
// TODO(loki): A lot of code using the new lambda callbacks now have access to
// the shared stack frame where before it didn't can be optimised to utilise the
// frame instead of re-deriving where data should be in the
// test_events_entry array
void loki_register_callback(std::vector<test_event_entry> &events,
std::string const &callback_name,
loki_callback callback)
@ -117,11 +97,34 @@ bool loki_chain_generator_db::get_tx(const crypto::hash &h, cryptonote::transact
return true;
}
std::vector<cryptonote::checkpoint_t>
loki_chain_generator_db::get_checkpoints_range(uint64_t start, uint64_t end, size_t num_desired_checkpoints) const
{
std::vector<cryptonote::checkpoint_t> result = {};
int offset = 1;
if (start >= end) offset = -1;
for (int index = static_cast<int>(start);
index != static_cast<int>(end);
index += offset)
{
if (result.size() >= num_desired_checkpoints) break;
if (blockchain[index].checkpointed) result.push_back(blockchain[index].checkpoint);
}
if (result.size() < num_desired_checkpoints && blockchain[end].checkpointed)
result.push_back(blockchain[end].checkpoint);
return result;
}
loki_chain_generator::loki_chain_generator(std::vector<test_event_entry> &events, const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks)
: db_(blocks_, tx_table_, block_table_)
, events_(events)
, hard_forks_(hard_forks)
{
bool init = lns_db_.init(lns::init_loki_name_system(""), 0, crypto::null_hash);
assert(init);
first_miner_.generate();
loki_blockchain_entry genesis = loki_chain_generator::create_genesis_block(first_miner_, 1338224400);
events_.push_back(genesis.block);
@ -187,6 +190,28 @@ loki_blockchain_entry &loki_chain_generator::add_block(loki_blockchain_entry con
tx_table_[tx_hash] = tx;
}
cryptonote::checkpoint_t immutable_checkpoint = {};
if (entry.block.major_version >= cryptonote::network_version_14_blink_lns && db_.get_immutable_checkpoint(&immutable_checkpoint, cryptonote::get_block_height(entry.block)))
{
uint64_t hf14_height = 0;
for (std::pair<uint8_t, uint64_t> hfs : hard_forks_)
{
if (hfs.first == cryptonote::network_version_14_blink_lns)
{
hf14_height = hfs.second;
break;
}
}
uint64_t start_height = std::max(hf14_height, lns_db_.height());
int64_t num_blocks = static_cast<int64_t>(immutable_checkpoint.height) - static_cast<int64_t>(start_height);
for (int64_t i = 0; i < num_blocks; i++)
{
loki_blockchain_entry const &other_entry = blocks_[start_height + i];
lns_db_.add_block(cryptonote::FAKECHAIN, other_entry.block, other_entry.txs);
}
}
// TODO(loki): State history culling and alt states
state_history_.emplace_hint(state_history_.end(), result.service_node_state);
@ -266,8 +291,21 @@ void loki_chain_generator::add_tx(cryptonote::transaction const &tx, bool can_be
events_.push_back(entry);
}
cryptonote::transaction
loki_chain_generator::create_and_add_loki_name_system_tx(cryptonote::account_base const &src,
uint16_t type,
void const *value,
size_t value_len,
std::string const &name,
bool kept_by_block)
{
cryptonote::transaction t = create_loki_name_system_tx(src, type, value, value_len, name);
add_tx(t, true /*can_be_added_to_blockchain*/, ""/*fail_msg*/, kept_by_block);
return t;
}
cryptonote::transaction loki_chain_generator::create_and_add_tx(const cryptonote::account_base &src,
const cryptonote::account_base &dest,
const cryptonote::account_public_address &dest,
uint64_t amount,
uint64_t fee,
bool kept_by_block)
@ -307,7 +345,7 @@ loki_blockchain_entry &loki_chain_generator::create_and_add_next_block(const std
}
cryptonote::transaction loki_chain_generator::create_tx(const cryptonote::account_base &src,
const cryptonote::account_base &dest,
const cryptonote::account_public_address &dest,
uint64_t amount,
uint64_t fee) const
{
@ -365,7 +403,7 @@ loki_chain_generator::create_registration_tx(const cryptonote::account_base &src
crypto::generate_signature(hash, service_node_keys.pub, service_node_keys.sec, signature);
add_service_node_register_to_tx_extra(extra, contributors, src_operator_cut, portions, exp_timestamp, signature);
add_service_node_contributor_to_tx_extra(extra, contributors.at(0));
loki_tx_builder(events_, result, top().block, src /*from*/, src /*to*/, amount, new_hf_version)
loki_tx_builder(events_, result, top().block, src /*from*/, src.get_keys().m_account_address /*to*/, amount, new_hf_version)
.with_tx_type(cryptonote::txtype::stake)
.with_unlock_time(unlock_time)
.with_extra(extra)
@ -390,7 +428,7 @@ cryptonote::transaction loki_chain_generator::create_staking_tx(const crypto::pu
if (new_hf_version < cryptonote::network_version_11_infinite_staking)
unlock_time = new_height + service_nodes::staking_num_lock_blocks(cryptonote::FAKECHAIN);
loki_tx_builder(events_, result, top().block, src /*from*/, src /*to*/, amount, new_hf_version)
loki_tx_builder(events_, result, top().block, src /*from*/, src.get_keys().m_account_address /*to*/, amount, new_hf_version)
.with_tx_type(cryptonote::txtype::stake)
.with_unlock_time(unlock_time)
.with_extra(extra)
@ -441,7 +479,7 @@ cryptonote::transaction loki_chain_generator::create_state_change_tx(service_nod
std::vector<uint8_t> extra;
const bool full_tx_made = cryptonote::add_service_node_state_change_to_tx_extra(result.extra, state_change_extra, get_hf_version_at(height + 1));
assert(full_tx_made);
if (fee) loki_tx_builder(events_, result, top().block, first_miner_, first_miner_, 0 /*amount*/, get_hf_version_at(height + 1)).with_tx_type(cryptonote::txtype::state_change).with_fee(fee).with_extra(extra).build();
if (fee) loki_tx_builder(events_, result, top().block, first_miner_, first_miner_.get_keys().m_account_address, 0 /*amount*/, get_hf_version_at(height + 1)).with_tx_type(cryptonote::txtype::state_change).with_fee(fee).with_extra(extra).build();
else
{
result.type = cryptonote::txtype::state_change;
@ -472,6 +510,40 @@ cryptonote::checkpoint_t loki_chain_generator::create_service_node_checkpoint(ui
return result;
}
cryptonote::transaction loki_chain_generator::create_loki_name_system_tx(cryptonote::account_base const &src,
uint16_t type,
void const *value,
size_t value_len,
std::string const &name) const
{
std::vector<uint8_t> extra;
cryptonote::tx_extra_loki_name_system data = {};
data.owner = src.get_keys().m_spend_ed25519_public_key;
data.type = type;
data.value = std::string(reinterpret_cast<char const *>(value), value_len);
data.name = name;
crypto::hash hash = data.make_signature_hash();
crypto_sign_ed25519_detached(data.signature.data,
nullptr,
reinterpret_cast<const unsigned char *>(hash.data),
sizeof(hash.data),
src.get_keys().m_spend_ed25519_secret_key.data);
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
cryptonote::block const &head = top().block;
uint64_t new_height = get_block_height(top().block) + 1;
uint8_t new_hf_version = get_hf_version_at(new_height);
cryptonote::transaction result = {};
loki_tx_builder(events_, result, head, src /*from*/, src.get_keys().m_account_address, 0, new_hf_version)
.with_tx_type(cryptonote::txtype::loki_name_system)
.with_extra(extra)
.build();
return result;
}
static void fill_nonce(cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height)
{
blk.nonce = 0;
@ -1048,7 +1120,7 @@ cryptonote::transaction make_registration_tx(std::vector<test_event_entry>& even
cryptonote::txtype tx_type = cryptonote::txtype::standard;
if (hf_version >= cryptonote::network_version_14_blink_lns) tx_type = cryptonote::txtype::stake; // NOTE: txtype stake was not introduced until HF14
loki_tx_builder(events, tx, head, account, account, amount, hf_version).with_tx_type(tx_type).with_extra(extra).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, head, account, account.get_keys().m_account_address, amount, hf_version).with_tx_type(tx_type).with_extra(extra).with_unlock_time(unlock_time).build();
events.push_back(tx);
return tx;
}
@ -1794,7 +1866,7 @@ cryptonote::transaction construct_tx_with_fee(std::vector<test_event_entry> &eve
uint64_t fee)
{
cryptonote::transaction tx;
loki_tx_builder(events, tx, blk_head, acc_from, acc_to, amount, cryptonote::network_version_7).with_fee(fee).build();
loki_tx_builder(events, tx, blk_head, acc_from, acc_to.get_keys().m_account_address, amount, cryptonote::network_version_7).with_fee(fee).build();
events.push_back(tx);
return tx;
}

View File

@ -54,6 +54,7 @@
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "misc_language.h"
#include "sqlite/sqlite3.h"
#include "blockchain_db/testdb.h"
#undef LOKI_DEFAULT_LOG_CATEGORY
@ -1089,7 +1090,7 @@ inline bool do_replay_file(const std::string& filename)
// NOTE(loki): These macros assume hardfork version 7 and are from the old Monero testing code
#define MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
cryptonote::transaction TX_NAME; \
loki_tx_builder(VEC_EVENTS, TX_NAME, HEAD, FROM, TO, AMOUNT, cryptonote::network_version_7).build(); \
loki_tx_builder(VEC_EVENTS, TX_NAME, HEAD, FROM, TO.get_keys().m_account_address, AMOUNT, cryptonote::network_version_7).build(); \
VEC_EVENTS.push_back(TX_NAME);
#define MAKE_TX_MIX_RCT(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
@ -1102,7 +1103,7 @@ inline bool do_replay_file(const std::string& filename)
#define MAKE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
{ \
cryptonote::transaction t; \
loki_tx_builder(VEC_EVENTS, t, HEAD, FROM, TO, AMOUNT, cryptonote::network_version_7).build(); \
loki_tx_builder(VEC_EVENTS, t, HEAD, FROM, TO.get_keys().m_account_address, AMOUNT, cryptonote::network_version_7).build(); \
SET_NAME.push_back(t); \
VEC_EVENTS.push_back(t); \
}
@ -1267,7 +1268,7 @@ class loki_tx_builder {
cryptonote::transaction& m_tx;
const cryptonote::block& m_head;
const cryptonote::account_base& m_from;
const cryptonote::account_base& m_to;
const cryptonote::account_public_address& m_to;
uint64_t m_amount;
uint64_t m_fee;
@ -1283,7 +1284,7 @@ public:
cryptonote::transaction& tx,
const cryptonote::block& head,
const cryptonote::account_base& from,
const cryptonote::account_base& to,
const cryptonote::account_public_address& to,
uint64_t amount,
uint8_t hf_version)
: m_events(events)
@ -1336,7 +1337,7 @@ public:
// TODO(loki): Eww we still depend on monero land test code
const auto nmix = 9;
fill_tx_sources_and_destinations(
m_events, m_head, m_from, m_to.get_keys().m_account_address, m_amount, m_fee, nmix, sources, destinations, &change_amount);
m_events, m_head, m_from, m_to, m_amount, m_fee, nmix, sources, destinations, &change_amount);
cryptonote::tx_destination_entry change_addr{ change_amount, m_from.get_keys().m_account_address, false /*is_subaddr*/ };
bool result = cryptonote::construct_tx(
@ -1363,19 +1364,21 @@ struct loki_chain_generator_db : public cryptonote::BaseTestDB
{
std::vector<loki_blockchain_entry> &blockchain;
std::unordered_map<crypto::hash, cryptonote::transaction> &tx_table; // TODO(loki): I want to store pointers to transactions but I get some memory corruption somewhere. Pls fix.
std::unordered_map<crypto::hash, loki_blockchain_entry> &block_table;
std::unordered_map<crypto::hash, loki_blockchain_entry> &block_table;
loki_chain_generator_db(std::vector<loki_blockchain_entry> &blockchain,
std::unordered_map<crypto::hash, cryptonote::transaction> &tx_table,
std::unordered_map<crypto::hash, loki_blockchain_entry> &block_table)
std::unordered_map<crypto::hash, cryptonote::transaction> &tx_table,
std::unordered_map<crypto::hash, loki_blockchain_entry> &block_table)
: blockchain(blockchain)
, tx_table(tx_table)
, block_table(block_table)
{
}
cryptonote::block get_block_from_height(const uint64_t &height) const override;
bool get_tx(const crypto::hash& h, cryptonote::transaction &tx) const override;
cryptonote::block get_block_from_height(const uint64_t &height) const override;
bool get_tx(const crypto::hash& h, cryptonote::transaction &tx) const override;
std::vector<cryptonote::checkpoint_t> get_checkpoints_range(uint64_t start, uint64_t end, size_t num_desired_checkpoints) const override;
uint64_t height() const override { return blockchain.size(); }
};
struct loki_service_node_contribution
@ -1386,23 +1389,23 @@ struct loki_service_node_contribution
struct loki_chain_generator
{
mutable std::unordered_map<crypto::public_key, crypto::secret_key> service_node_keys_;
service_nodes::service_node_list::state_set state_history_;
service_nodes::service_node_keys get_cached_keys(const crypto::public_key &pubkey) const;
// TODO(loki): I want to store pointers to transactions but I get some memory corruption somewhere. Pls fix.
// We already store blockchain_entries in block_ vector which stores the actual backing transaction entries.
std::unordered_map<crypto::hash, cryptonote::transaction> tx_table_;
std::unordered_map<crypto::hash, loki_blockchain_entry> block_table_; // TODO(loki): Hmm takes a copy. But its easier to work this way, particularly for storing alt blocks
std::vector<loki_blockchain_entry> blocks_;
loki_chain_generator_db db_;
uint8_t hf_version_ = cryptonote::network_version_7;
std::vector<test_event_entry>& events_;
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks_;
cryptonote::account_base first_miner_;
std::unordered_map<crypto::hash, cryptonote::transaction> tx_table_;
std::unordered_map<crypto::hash, loki_blockchain_entry> block_table_; // TODO(loki): Hmm takes a copy. But its easier to work this way, particularly for storing alt blocks
std::vector<loki_blockchain_entry> blocks_;
mutable std::unordered_map<crypto::public_key, crypto::secret_key> service_node_keys_;
service_nodes::service_node_list::state_set state_history_;
uint64_t last_cull_height_ = 0;
lns::name_system_db lns_db_;
loki_chain_generator_db db_;
uint8_t hf_version_ = cryptonote::network_version_7;
std::vector<test_event_entry>& events_;
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks_;
cryptonote::account_base first_miner_;
loki_chain_generator(std::vector<test_event_entry> &events, const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks);
~loki_chain_generator() { sqlite3_close_v2(lns_db_.db); }
uint64_t height() const { return cryptonote::get_block_height(blocks_.back().block); }
const std::vector<loki_blockchain_entry>& blocks() const { return blocks_; }
@ -1412,6 +1415,7 @@ struct loki_chain_generator
service_nodes::quorum_manager top_quorum() const;
service_nodes::quorum_manager quorum(uint64_t height) const;
std::shared_ptr<const service_nodes::quorum> get_quorum(service_nodes::quorum_type type, uint64_t height) const;
service_nodes::service_node_keys get_cached_keys(const crypto::public_key &pubkey) const;
cryptonote::account_base add_account();
loki_blockchain_entry &add_block(loki_blockchain_entry const &entry, bool can_be_added_to_blockchain = true, std::string const &fail_msg = {});
@ -1427,14 +1431,15 @@ 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.
cryptonote::transaction create_and_add_tx (const cryptonote::account_base& src, const cryptonote::account_base& dest, uint64_t amount, uint64_t fee = TESTS_DEFAULT_FEE, bool kept_by_block = false);
cryptonote::transaction create_and_add_loki_name_system_tx(cryptonote::account_base const &src, uint16_t type, void const *value, size_t value_len, std::string const &name, 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);
cryptonote::transaction create_and_add_staking_tx (const crypto::public_key &pub_key, const cryptonote::account_base &src, uint64_t amount, bool kept_by_block = false);
loki_blockchain_entry &create_and_add_next_block (const std::vector<cryptonote::transaction>& txs = {}, cryptonote::checkpoint_t const *checkpoint = nullptr, bool can_be_added_to_blockchain = true, std::string const &fail_msg = {});
// NOTE: Create transactions but don't add to events_
cryptonote::transaction create_tx (const cryptonote::account_base &src, const cryptonote::account_base &dest, uint64_t amount, uint64_t fee) const;
cryptonote::transaction create_tx(const cryptonote::account_base &src, const cryptonote::account_public_address &dest, uint64_t amount, uint64_t fee) const;
cryptonote::transaction create_registration_tx(const cryptonote::account_base &src,
const cryptonote::keypair &service_node_keys = cryptonote::keypair::generate(hw::get_device("default")),
uint64_t src_portions = STAKING_PORTIONS,
@ -1444,6 +1449,7 @@ struct loki_chain_generator
cryptonote::transaction create_staking_tx (const crypto::public_key& pub_key, const cryptonote::account_base &src, uint64_t amount) const;
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;
cryptonote::transaction create_loki_name_system_tx (cryptonote::account_base const &src, uint16_t type, void const *value, size_t value_len, std::string const &name) const;
loki_blockchain_entry create_genesis_block(const cryptonote::account_base &miner, uint64_t timestamp);
loki_blockchain_entry create_next_block(const std::vector<cryptonote::transaction>& txs = {}, cryptonote::checkpoint_t const *checkpoint = nullptr, uint64_t total_fee = 0);

View File

@ -112,7 +112,7 @@ static void make_rct_tx(eventV& events,
{
txs.emplace_back();
bool success = loki_tx_builder(events, txs.back(), blk_head, from, to, amount, cryptonote::network_version_7).build();
bool success = loki_tx_builder(events, txs.back(), blk_head, from, to.get_keys().m_account_address, amount, cryptonote::network_version_7).build();
/// TODO: beter error message
if (!success) throw std::exception();
events.push_back(txs.back());

View File

@ -123,6 +123,9 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(loki_core_test_deregister_zero_fee);
GENERATE_AND_PLAY(loki_core_test_deregister_on_split);
GENERATE_AND_PLAY(loki_core_test_state_change_ip_penalty_disallow_dupes);
GENERATE_AND_PLAY(loki_name_system_handles_duplicates);
GENERATE_AND_PLAY(loki_name_system_invalid_tx_extra_params);
GENERATE_AND_PLAY(loki_name_system_name_value_max_lengths);
GENERATE_AND_PLAY(loki_service_nodes_alt_quorums);
GENERATE_AND_PLAY(loki_service_nodes_checkpoint_quorum_size);
GENERATE_AND_PLAY(loki_service_nodes_gen_nodes);

View File

@ -131,8 +131,8 @@ bool gen_double_spend_in_the_same_block::generate(std::vector<test_event_entry>&
uint64_t amount = MK_COINS(10);
cryptonote::account_base const &miner = gen.first_miner_;
cryptonote::account_base bob = gen.add_account();
cryptonote::transaction tx_1 = gen.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = gen.create_and_add_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_1 = gen.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = gen.create_and_add_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
std::string const fail_msg =
(kept_by_block) ? "kept_by_block is true, double spending transactions can be added (incase of reorgs)"
@ -172,8 +172,8 @@ bool gen_double_spend_in_different_blocks::generate(std::vector<test_event_entry
else gen.add_event_msg("Double spending transaction kept by block false, disallowed");
uint64_t amount = MK_COINS(10);
cryptonote::transaction tx_1 = gen.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = gen.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_1 = gen.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = gen.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
std::string const fail_msg =
(kept_by_block) ? "kept_by_block is true, double spending transactions can be added (incase of reorgs)"
@ -218,8 +218,8 @@ bool gen_double_spend_in_alt_chain_in_the_same_block::generate(std::vector<test_
uint64_t amount = MK_COINS(10);
cryptonote::account_base const &miner = fork.first_miner_;
cryptonote::account_base bob = fork.add_account();
cryptonote::transaction tx_1 = fork.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = fork.create_and_add_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_1 = fork.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = fork.create_and_add_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
std::string const fail_msg =
(kept_by_block) ? "kept_by_block is true, double spending transactions can be added (incase of reorgs)"
@ -260,8 +260,8 @@ bool gen_double_spend_in_alt_chain_in_different_blocks::generate(std::vector<tes
else fork.add_event_msg("Double spending transaction kept by block false, disallowed");
uint64_t amount = MK_COINS(10);
cryptonote::transaction tx_1 = fork.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = fork.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_1 = fork.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = fork.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
std::string const fail_msg =
(kept_by_block) ? "kept_by_block is true, double spending transactions can be added (incase of reorgs)"
@ -294,8 +294,8 @@ bool gen_double_spend_in_different_chains::generate(std::vector<test_event_entry
uint64_t amount = MK_COINS(10);
cryptonote::account_base const &miner = gen.first_miner_;
cryptonote::account_base bob = gen.add_account();
cryptonote::transaction tx_1 = gen.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = gen.create_tx(miner, bob, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_1 = gen.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
cryptonote::transaction tx_2 = gen.create_tx(miner, bob.get_keys().m_account_address, amount, TESTS_DEFAULT_FEE);
auto fork = gen;
gen.add_tx(tx_1, true /*can_be_added_to_blockchain*/, "", true /*kept_by_block*/);

View File

@ -121,7 +121,7 @@ bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
{
// Create txs with fee greater than the block reward
std::vector<cryptonote::transaction> txs;
txs.push_back(gen.create_and_add_tx(gen.first_miner_, alice, MK_COINS(1), MK_COINS(100) /*fee*/, false /*kept_by_block*/));
txs.push_back(gen.create_and_add_tx(gen.first_miner_, alice.get_keys().m_account_address, MK_COINS(1), MK_COINS(100) /*fee*/, false /*kept_by_block*/));
loki_blockchain_entry entry = gen.create_next_block(txs);
cryptonote::transaction &miner_tx = entry.block.miner_tx;
@ -132,7 +132,7 @@ bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
{
// Set kept_by_block = true
std::vector<cryptonote::transaction> txs;
txs.push_back(gen.create_and_add_tx(gen.first_miner_, alice, MK_COINS(1), MK_COINS(100) /*fee*/, true /*kept_by_block*/));
txs.push_back(gen.create_and_add_tx(gen.first_miner_, alice.get_keys().m_account_address, MK_COINS(1), MK_COINS(100) /*fee*/, true /*kept_by_block*/));
loki_blockchain_entry entry = gen.create_next_block(txs);
cryptonote::transaction &miner_tx = entry.block.miner_tx;

View File

@ -31,6 +31,11 @@
#include "loki_tests.h"
#include "cryptonote_core/service_node_list.h"
extern "C"
{
#include <sodium.h>
};
#undef LOKI_DEFAULT_LOG_CATEGORY
#define LOKI_DEFAULT_LOG_CATEGORY "sn_core_tests"
@ -521,7 +526,7 @@ bool loki_core_block_reward_unpenalized::generate(std::vector<test_event_entry>&
int constexpr NUM_TXS = 60;
std::vector<cryptonote::transaction> txs(NUM_TXS);
for (int i = 0; i < NUM_TXS; i++)
txs[i] = gen.create_and_add_tx(gen.first_miner_, dummy, MK_COINS(5));
txs[i] = gen.create_and_add_tx(gen.first_miner_, dummy.get_keys().m_account_address, MK_COINS(5));
gen.create_and_add_next_block(txs);
uint64_t unpenalized_block_reward = cryptonote::block_reward_unpenalized_formula_v8(gen.height());
@ -568,10 +573,10 @@ bool loki_core_fee_burning::generate(std::vector<test_event_entry>& events)
auto add_burning_tx = [&events, &gen, &dummy, newest_hf](const std::array<uint64_t, 3> &send_fee_burn) {
auto send = send_fee_burn[0], fee = send_fee_burn[1], burn = send_fee_burn[2];
transaction tx = gen.create_tx(gen.first_miner_, dummy, send, fee);
transaction tx = gen.create_tx(gen.first_miner_, dummy.get_keys().m_account_address, send, fee);
std::vector<uint8_t> burn_extra;
add_burned_amount_to_tx_extra(burn_extra, burn);
loki_tx_builder(events, tx, gen.blocks().back().block, gen.first_miner_, dummy, send, newest_hf).with_fee(fee).with_extra(burn_extra).build();
loki_tx_builder(events, tx, gen.blocks().back().block, gen.first_miner_, dummy.get_keys().m_account_address, send, newest_hf).with_fee(fee).with_extra(burn_extra).build();
gen.add_tx(tx);
return tx;
};
@ -718,7 +723,7 @@ bool loki_core_test_deregister_preferred::generate(std::vector<test_event_entry>
/// generate transactions to fill up txpool entirely
for (auto i = 0u; i < 45; ++i) {
gen.create_and_add_tx(miner, alice, MK_COINS(1), TESTS_DEFAULT_FEE * 100);
gen.create_and_add_tx(miner, alice.get_keys().m_account_address, MK_COINS(1), TESTS_DEFAULT_FEE * 100);
}
/// generate two deregisters
@ -987,6 +992,414 @@ bool loki_core_test_state_change_ip_penalty_disallow_dupes::generate(std::vector
return true;
}
bool loki_name_system_handles_duplicates::generate(std::vector<test_event_entry> &events)
{
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
loki_chain_generator gen(events, hard_forks);
cryptonote::account_base miner = gen.first_miner_;
cryptonote::account_base bob = gen.add_account();
{
gen.add_blocks_until_version(hard_forks.back().first);
gen.add_n_blocks(30); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
cryptonote::transaction transfer = gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(200));
gen.create_and_add_next_block({transfer});
gen.add_mined_money_unlock_blocks();
int constexpr NUM_SERVICE_NODES = service_nodes::CHECKPOINT_QUORUM_SIZE;
std::vector<cryptonote::transaction> registration_txs(NUM_SERVICE_NODES);
for (auto i = 0u; i < NUM_SERVICE_NODES; ++i)
registration_txs[i] = gen.create_and_add_registration_tx(gen.first_miner());
gen.create_and_add_next_block(registration_txs);
// NOTE: Add blocks until we get to the first height that has a checkpointing quorum AND there are service nodes in the quorum.
int const MAX_TRIES = 16;
int tries = 0;
for (; tries < MAX_TRIES; tries++)
{
gen.add_blocks_until_next_checkpointable_height();
std::shared_ptr<const service_nodes::quorum> quorum = gen.get_quorum(service_nodes::quorum_type::checkpointing, gen.height());
if (quorum && quorum->validators.size()) break;
}
assert(tries != MAX_TRIES);
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
}
crypto::ed25519_public_key const &miner_key = miner.get_keys().m_spend_ed25519_public_key;
crypto::ed25519_public_key const &bob_key = bob.get_keys().m_spend_ed25519_public_key;
std::string messenger_name = "MyFriendlyDisplayName";
char messenger_key[lns::MESSENGER_PUBLIC_KEY_LENGTH] = {};
messenger_key[0] = 5;
memcpy(messenger_key + 1, miner_key.data, sizeof(miner_key));
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),
messenger_key,
loki::array_count(messenger_key),
messenger_name);
cryptonote::transaction bar2 =
gen.create_and_add_loki_name_system_tx(miner,
static_cast<uint16_t>(lns::mapping_type::lokinet),
miner_key.data,
sizeof(miner_key),
messenger_name);
cryptonote::transaction bar3 =
gen.create_and_add_loki_name_system_tx(miner,
custom_type,
miner_key.data,
sizeof(miner_key),
messenger_name);
// NOTE: But don't allow duplicates if the type and name are the same (i.e. dupe the messenger entry but different owner)
cryptonote::transaction bar4 =
gen.create_and_add_loki_name_system_tx(bob,
static_cast<uint16_t>(lns::mapping_type::messenger),
messenger_key,
loki::array_count(messenger_key),
messenger_name);
gen.create_and_add_next_block({bar, bar2, bar3, bar4});
}
uint64_t height_of_lns_entry = gen.height();
gen.add_blocks_until_next_checkpointable_height();
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
gen.add_blocks_until_next_checkpointable_height();
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
gen.add_blocks_until_next_checkpointable_height();
gen.add_service_node_checkpoint(gen.height(), service_nodes::CHECKPOINT_MIN_VOTES);
loki_register_callback(events, "check_lns_entries", [&events, height_of_lns_entry, miner_key, bob_key, messenger_key, messenger_name, custom_type](cryptonote::core &c, size_t ev_index)
{
DEFINE_TESTS_ERROR_CONTEXT("check_lns_entries");
lns::name_system_db const &lns_db = c.get_blockchain_storage().name_system_db();
lns::user_record user = lns_db.get_user_by_key(miner_key);
CHECK_EQ(user.loaded, true);
CHECK_EQ(user.id, 1);
CHECK_EQ(miner_key, user.key);
lns::mapping_record mappings = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::messenger), messenger_key, sizeof(messenger_key));
CHECK_EQ(mappings.loaded, true);
CHECK_EQ(mappings.type, static_cast<uint16_t>(lns::mapping_type::messenger));
CHECK_EQ(mappings.name, std::string(messenger_name));
CHECK_EQ(mappings.value, std::string(messenger_key, sizeof(messenger_key)));
CHECK_EQ(mappings.register_height, height_of_lns_entry);
CHECK_EQ(mappings.user_id, user.id);
lns::mapping_record mappings2 = lns_db.get_mapping(static_cast<uint16_t>(lns::mapping_type::lokinet), miner_key.data, sizeof(miner_key));
CHECK_EQ(mappings2.loaded, true);
CHECK_EQ(mappings2.type, static_cast<uint16_t>(lns::mapping_type::lokinet));
CHECK_EQ(mappings2.name, std::string(messenger_name));
CHECK_EQ(mappings2.value, std::string((char *)miner_key.data, sizeof(miner_key)));
CHECK_EQ(mappings2.register_height, height_of_lns_entry);
CHECK_EQ(mappings2.user_id, user.id);
lns::mapping_record mappings3 = lns_db.get_mapping(custom_type, miner_key.data, sizeof(miner_key.data));
CHECK_EQ(mappings3.loaded, true);
CHECK_EQ(mappings3.type, custom_type);
CHECK_EQ(mappings3.name, std::string(messenger_name));
CHECK_EQ(mappings3.value, std::string((char *)miner_key.data, sizeof(miner_key)));
CHECK_EQ(mappings3.register_height, height_of_lns_entry);
CHECK_EQ(mappings3.user_id, user.id);
// NOTE: Although bob sent a transaction under a new key, it was not
// accepted because the name they are reserving in LNS is already taken.
// Since we make additions to the DB transactional, his user account should not
// be committed to the DB.
lns::user_record user2 = lns_db.get_user_by_key(bob_key);
CHECK_EQ(user2.loaded, false);
return true;
});
return true;
}
bool loki_name_system_invalid_tx_extra_params::generate(std::vector<test_event_entry> &events)
{
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
loki_chain_generator gen(events, hard_forks);
cryptonote::account_base miner = gen.first_miner_;
gen.add_blocks_until_version(hard_forks.back().first);
gen.add_n_blocks(30); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
crypto::ed25519_public_key const &miner_key = miner.get_keys().m_spend_ed25519_public_key;
// Manually construct transaction with invalid tx extra
{
auto make_lns_tx_with_custom_extra = [](loki_chain_generator &gen,
std::vector<test_event_entry> &events,
cryptonote::account_base const &src,
cryptonote::tx_extra_loki_name_system &data,
bool valid,
char const *reason) -> void {
crypto::hash hash = data.make_signature_hash();
crypto_sign_ed25519_detached(data.signature.data,
nullptr,
reinterpret_cast<const unsigned char *>(hash.data),
sizeof(hash.data),
src.get_keys().m_spend_ed25519_secret_key.data);
std::vector<uint8_t> extra;
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
cryptonote::transaction tx = {};
loki_tx_builder(
events, tx, gen.top().block, src /*from*/, src.get_keys().m_account_address, 0, new_hf_version)
.with_tx_type(cryptonote::txtype::loki_name_system)
.with_extra(extra)
.build();
gen.add_tx(tx, valid /*can_be_added_to_blockchain*/, reason, false /*kept_by_block*/);
};
cryptonote::tx_extra_loki_name_system valid_data = {};
valid_data.owner = miner.get_keys().m_spend_ed25519_public_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.name = "my_lns_name";
// Blockchain name too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = std::string(lns::BLOCKCHAIN_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Wallet to name in LNS too long");
}
// Blockchain name empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = {};
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Empty wallet name in LNS is invalid");
}
// Blockchain value (wallet address) is too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::BLOCKCHAIN_WALLET_ADDRESS_LENGTH + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Wallet value in LNS too long");
}
// Blockchain value (wallet address) is too short
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::BLOCKCHAIN_WALLET_ADDRESS_LENGTH - 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Blockchain) Wallet value in LNS too short");
}
valid_data.type = static_cast<uint16_t>(lns::mapping_type::lokinet);
// Lokinet domain name too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = std::string(lns::LOKINET_DOMAIN_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Domain name in LNS too long");
}
// Lokinet domain name empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = {};
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Empty domain name in LNS is invalid");
}
// Lokinet domain value too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::LOKINET_ADDRESS_LENGTH + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Domain value in LNS too long");
}
// Lokinet domain value too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::LOKINET_ADDRESS_LENGTH - 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Lokinet) Domain value in LNS too short");
}
// Messenger value invalid, messenger keys require a 33 byte key where the first byte is a 0x05
std::stringstream stream;
valid_data.type = static_cast<uint16_t>(lns::mapping_type::messenger);
{
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;
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_LENGTH] = {};
messenger_key[0] = 5;
memcpy(messenger_key + 1, miner_key.data, sizeof(miner_key));
valid_data.value = std::string(messenger_key, sizeof(messenger_key));
{
cryptonote::tx_extra_loki_name_system data = valid_data;
stream << "(Messenger) Key should be valid, prefixed with 0x05: " << data.value;
make_lns_tx_with_custom_extra(gen, events, miner, data, true, stream.str().c_str());
stream.clear();
}
// Messenger value too short
// We added valid tx prior, we should update name to avoid conflict names in messenger land and test other invalid params
valid_data.name = "new_friendly_name";
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::MESSENGER_PUBLIC_KEY_LENGTH - 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, value too short");
}
// Messenger value too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.value = std::string(lns::MESSENGER_PUBLIC_KEY_LENGTH + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, value too long");
}
// Messenger name too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = std::string(lns::MESSENGER_DISPLAY_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, name too long");
}
// Messenger name empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.name = {};
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Messenger) User id, name too long");
}
// Generic name empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.type = 1111;
data.name = {};
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Generic) Name empty");
}
// Generic valid empty
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.type = 1111;
data.value = {};
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Generic) Value empty");
}
// Generic name too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.type = 1111;
data.name = std::string(lns::GENERIC_NAME_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Generic) Name empty");
}
// Generic value too long
{
cryptonote::tx_extra_loki_name_system data = valid_data;
data.type = 1111;
data.value = std::string(lns::GENERIC_VALUE_MAX + 1, 'A');
make_lns_tx_with_custom_extra(gen, events, miner, data, false, "(Generic) Value too long");
}
}
return true;
}
bool loki_name_system_name_value_max_lengths::generate(std::vector<test_event_entry> &events)
{
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = loki_generate_sequential_hard_fork_table();
loki_chain_generator gen(events, hard_forks);
cryptonote::account_base miner = gen.first_miner_;
gen.add_blocks_until_version(hard_forks.back().first);
gen.add_n_blocks(30); /// generate some outputs and unlock them
gen.add_mined_money_unlock_blocks();
crypto::ed25519_public_key const &miner_key = miner.get_keys().m_spend_ed25519_public_key;
auto make_lns_tx_with_custom_extra = [](loki_chain_generator &gen,
std::vector<test_event_entry> &events,
cryptonote::account_base const &src,
cryptonote::tx_extra_loki_name_system &data) -> void {
crypto::hash hash = data.make_signature_hash();
crypto_sign_ed25519_detached(data.signature.data,
nullptr,
reinterpret_cast<const unsigned char *>(hash.data),
sizeof(hash.data),
src.get_keys().m_spend_ed25519_secret_key.data);
std::vector<uint8_t> extra;
cryptonote::add_loki_name_system_to_tx_extra(extra, data);
uint64_t new_height = cryptonote::get_block_height(gen.top().block) + 1;
uint8_t new_hf_version = gen.get_hf_version_at(new_height);
cryptonote::transaction tx = {};
loki_tx_builder(
events, tx, gen.top().block, src /*from*/, src.get_keys().m_account_address, 0, new_hf_version)
.with_tx_type(cryptonote::txtype::loki_name_system)
.with_extra(extra)
.build();
gen.add_tx(tx, true /*can_be_added_to_blockchain*/, "", false /*kept_by_block*/);
};
cryptonote::tx_extra_loki_name_system data = {};
data.owner = miner.get_keys().m_spend_ed25519_public_key;
data.value = cryptonote::get_account_address_as_str(cryptonote::FAKECHAIN, false, miner.get_keys().m_account_address);
// Blockchain
{
data.type = static_cast<uint16_t>(lns::mapping_type::blockchain);
data.name = std::string(lns::BLOCKCHAIN_NAME_MAX, 'A');
data.value = std::string(lns::BLOCKCHAIN_WALLET_ADDRESS_LENGTH, 'Z');
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
// Lokinet
{
data.type = static_cast<uint16_t>(lns::mapping_type::lokinet);
data.name = std::string(lns::LOKINET_DOMAIN_NAME_MAX, 'A');
data.value = std::string(lns::LOKINET_ADDRESS_LENGTH, 'Z');
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
// Messenger
{
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_LENGTH, 'Z');
data.value[0] = 0x05;
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
// Generic
{
data.type = 1111;
data.name = std::string(lns::GENERIC_NAME_MAX, 'A');
data.value = std::string(lns::GENERIC_VALUE_MAX, 'Z');
make_lns_tx_with_custom_extra(gen, events, miner, data);
}
return true;
}
// NOTE: Generate forked block, check that alternative quorums are generated and accessible
bool loki_service_nodes_alt_quorums::generate(std::vector<test_event_entry>& events)
{
@ -1107,7 +1520,7 @@ bool loki_service_nodes_gen_nodes::generate(std::vector<test_event_entry> &event
gen.add_n_blocks(10);
gen.add_mined_money_unlock_blocks();
const auto tx0 = gen.create_and_add_tx(miner, alice, MK_COINS(101));
const auto tx0 = gen.create_and_add_tx(miner, alice.get_keys().m_account_address, MK_COINS(101));
gen.create_and_add_next_block({tx0});
gen.add_mined_money_unlock_blocks();
@ -1426,4 +1839,3 @@ bool loki_service_nodes_insufficient_contribution::generate(std::vector<test_eve
return true;
}

View File

@ -51,6 +51,9 @@ struct loki_core_test_deregister_too_old
struct loki_core_test_deregister_zero_fee : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_core_test_deregister_on_split : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_core_test_state_change_ip_penalty_disallow_dupes : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_handles_duplicates : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_invalid_tx_extra_params : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_name_system_name_value_max_lengths : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_service_nodes_alt_quorums : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_service_nodes_checkpoint_quorum_size : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct loki_service_nodes_gen_nodes : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };

View File

@ -68,20 +68,20 @@ bool gen_ring_signature_1::generate(std::vector<test_event_entry>& events) const
gen.add_mined_money_unlock_blocks();
std::vector<cryptonote::transaction> txs;
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(1)) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(1)) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, some_account_2, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1.get_keys().m_account_address, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1.get_keys().m_account_address, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1.get_keys().m_account_address, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1.get_keys().m_account_address, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1.get_keys().m_account_address, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, some_account_2.get_keys().m_account_address, MK_COINS(20) + rnd_20) );
gen.create_and_add_next_block(txs);
@ -89,7 +89,7 @@ bool gen_ring_signature_1::generate(std::vector<test_event_entry>& events) const
DO_CALLBACK(events, "check_balances_1");
auto tx = gen.create_and_add_tx(bob, alice, MK_COINS(129) + 2 * rnd_11 + rnd_20 + 3 * rnd_29 - TESTS_DEFAULT_FEE);
auto tx = gen.create_and_add_tx(bob, alice.get_keys().m_account_address, MK_COINS(129) + 2 * rnd_11 + rnd_20 + 3 * rnd_29 - TESTS_DEFAULT_FEE);
gen.create_and_add_next_block({tx});
DO_CALLBACK(events, "check_balances_2");

View File

@ -195,7 +195,7 @@ bool gen_tx_big_version::generate(std::vector<test_event_entry>& events) const
fill_tx_sources_and_destinations(events, blk_money_unlocked, miner_account, get_address(miner_account), MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), -1).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), -1).build();
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(tx);
@ -215,43 +215,43 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const
transaction tx = {};
uint64_t unlock_time = 0;
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked) - 1;
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked);
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked) + 1;
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked) + 2;
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = ts_start - 1;
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = time(0) + 60 * 60;
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
@ -276,13 +276,13 @@ bool gen_tx_input_is_not_txin_to_key::generate(std::vector<test_event_entry>& ev
DO_CALLBACK(events, "mark_invalid_tx");
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vin.push_back(txin_to_script());
events.push_back(tx);
DO_CALLBACK(events, "mark_invalid_tx");
tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vin.push_back(txin_to_scripthash());
events.push_back(tx);
@ -315,7 +315,7 @@ bool gen_tx_no_inputs_has_outputs::generate(std::vector<test_event_entry>& event
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vin.clear();
DO_CALLBACK(events, "mark_invalid_tx");
@ -333,7 +333,7 @@ bool gen_tx_has_inputs_no_outputs::generate(std::vector<test_event_entry>& event
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.clear();
DO_CALLBACK(events, "mark_invalid_tx"); // NOTE(loki): This used to be valid in Monero pre RCT, but not anymore with our transactions because we start with RCT type TXs
@ -379,7 +379,7 @@ bool gen_tx_input_wo_key_offsets::generate(std::vector<test_event_entry>& events
fill_tx_sources_and_destinations(events, blk_money_unlocked, miner_account, get_address(miner_account), MK_COINS(1), TESTS_DEFAULT_FEE, CRYPTONOTE_DEFAULT_TX_MIXIN, sources, destinations);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
while (!in_to_key.key_offsets.empty())
in_to_key.key_offsets.pop_back();
@ -406,7 +406,7 @@ bool gen_tx_key_offset_points_to_foreign_key::generate(std::vector<test_event_en
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction bob_tx = {};
loki_tx_builder(events, bob_tx, blk_money_unlocked, bob_account, miner_account, MK_COINS(15) + 1 - TESTS_DEFAULT_FEE, cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
loki_tx_builder(events, bob_tx, blk_money_unlocked, bob_account, miner_account.get_keys().m_account_address, MK_COINS(15) + 1 - TESTS_DEFAULT_FEE, cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
std::vector<tx_source_entry> sources_alice;
std::vector<tx_destination_entry> destinations_alice;
@ -437,7 +437,7 @@ bool gen_tx_sender_key_offset_not_exist::generate(std::vector<test_event_entry>&
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
in_to_key.key_offsets.front() = std::numeric_limits<uint64_t>::max();
@ -525,7 +525,7 @@ bool gen_tx_key_image_not_derive_from_tx_key::generate(std::vector<test_event_en
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
// Use fake key image
@ -553,7 +553,7 @@ bool gen_tx_key_image_is_invalid::generate(std::vector<test_event_entry>& events
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
in_to_key.k_image = generate_invalid_key_image();
@ -637,7 +637,7 @@ bool gen_tx_txout_to_key_has_invalid_key::generate(std::vector<test_event_entry>
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
txout_to_key& out_to_key = boost::get<txout_to_key>(tx.vout.front().target);
out_to_key.key = generate_invalid_pub_key();
@ -673,7 +673,7 @@ bool gen_tx_output_with_zero_amount::generate(std::vector<test_event_entry>& eve
#else
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.front().amount = 0;
#endif
@ -692,14 +692,14 @@ bool gen_tx_output_is_not_txout_to_key::generate(std::vector<test_event_entry>&
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.back().target = txout_to_script();
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(tx);
tx = {};
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.back().target = txout_to_scripthash();
DO_CALLBACK(events, "mark_invalid_tx");
@ -724,7 +724,7 @@ bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& even
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction miner_tx = {};
loki_tx_builder(events, miner_tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(60), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
loki_tx_builder(events, miner_tx, blk_money_unlocked, miner_account, miner_account.get_keys().m_account_address, MK_COINS(60), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
// TX without signatures
DO_CALLBACK(events, "mark_invalid_tx");
@ -744,7 +744,7 @@ bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& even
events.push_back(serialized_transaction(sr_tx));
transaction bob_tx = {};
loki_tx_builder(events, bob_tx, blk_money_unlocked, bob_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
loki_tx_builder(events, bob_tx, blk_money_unlocked, bob_account, miner_account.get_keys().m_account_address, MK_COINS(1), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
// TX without signatures
DO_CALLBACK(events, "mark_invalid_tx");

View File

@ -118,7 +118,7 @@ static uint32_t lcg()
get_test_options(): hard_forks{{std::make_pair(cryptonote::network_version_7, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)1)}} {} \
} opts; \
cryptonote::Blockchain *bc = &bc_objects.m_blockchain; \
bool r = bc->init(new ::TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0); \
bool r = bc->init(new ::TestDB(), nullptr /*lns_db*/, cryptonote::FAKECHAIN, true, &opts.test_options, 0); \
ASSERT_TRUE(r)
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW)

View File

@ -89,7 +89,7 @@ bool get_output_distribution(uint64_t amount, uint64_t from, uint64_t to, uint64
get_test_options():hard_forks{{std::make_pair((uint8_t)0, (uint64_t)0)}}{}
} opts;
cryptonote::Blockchain *blockchain = &bc.m_blockchain;
bool r = blockchain->init(new TestDB(test_distribution_size), cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL);
bool r = blockchain->init(new TestDB(test_distribution_size), nullptr /*lns_db*/, cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL);
return r && blockchain->get_output_distribution(amount, from, to, start_height, distribution, base);
}