mirror of https://github.com/oxen-io/oxen-core.git
Add support for Loki Name Service on the backend
This commit is contained in:
parent
623a354118
commit
dc69d237e6
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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(×tamp);
|
||||
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(×tamp);
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ? ®test_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 ? ®test_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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -89,6 +89,7 @@ extern "C"
|
|||
{
|
||||
#include "crypto/keccak.h"
|
||||
#include "crypto/crypto-ops.h"
|
||||
#include <sodium.h>
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"); \
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*/);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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); };
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue