forked from townforge/townforge
cc: save events to the db
This makes them retrievable from a snapshot, after a restart, and after a reorg that crosses a game update
This commit is contained in:
parent
b89e696a80
commit
761d212b53
@ -36,6 +36,7 @@
|
||||
#include "common/command_line.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cc/cc_config.h"
|
||||
#include "cc/cc_game_events.h"
|
||||
#include "cryptonote_basic/blobdatatype.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/difficulty.h"
|
||||
@ -1876,6 +1877,10 @@ public:
|
||||
virtual void remove_cc_shares(uint32_t city, uint64_t height) = 0;
|
||||
virtual bool get_cc_shares(uint32_t city, uint64_t height, cc_shares_data_t &sd) const = 0;
|
||||
|
||||
virtual void add_cc_events(uint64_t height, const std::vector<cc::game_update_event_t> &events) = 0;
|
||||
virtual void remove_cc_events(uint64_t height) = 0;
|
||||
virtual bool get_cc_events(uint64_t height, uint32_t account, uint32_t flag, std::vector<cc::game_update_event_t> &events) const = 0;
|
||||
|
||||
// CC non virtual helpers, calls the virtual ones
|
||||
bool does_cc_account_exist(uint32_t id) const;
|
||||
bool does_cc_city_exist(uint32_t id) const;
|
||||
|
@ -190,6 +190,55 @@ int BlockchainLMDB::compare_string(const MDB_val *a, const MDB_val *b)
|
||||
return strcmp(va, vb);
|
||||
}
|
||||
|
||||
enum event_match_t: uint32_t { em_account, em_account_flag, em_account_flag_event };
|
||||
int BlockchainLMDB::compare_events(const MDB_val *a, const MDB_val *b)
|
||||
{
|
||||
// a[1] size is an int which tells is how much of the record to match against
|
||||
const uint32_t match = a[1].mv_size;
|
||||
|
||||
const char *aptr = (const char*)a->mv_data;
|
||||
const char *bptr = (const char*)b->mv_data;
|
||||
uint32_t va32, vb32;
|
||||
|
||||
memcpy(&va32, aptr, sizeof(va32));
|
||||
memcpy(&vb32, bptr, sizeof(vb32));
|
||||
if (va32 < vb32)
|
||||
return -1;
|
||||
if (va32 > vb32)
|
||||
return 1;
|
||||
if (match == em_account)
|
||||
return 0;
|
||||
|
||||
aptr += sizeof(va32);
|
||||
bptr += sizeof(vb32);
|
||||
|
||||
memcpy(&va32, aptr, sizeof(va32));
|
||||
memcpy(&vb32, bptr, sizeof(vb32));
|
||||
if (va32 < vb32)
|
||||
return -1;
|
||||
if (va32 > vb32)
|
||||
return 1;
|
||||
if (match == em_account_flag)
|
||||
return 0;
|
||||
|
||||
aptr += sizeof(va32);
|
||||
bptr += sizeof(vb32);
|
||||
|
||||
const ssize_t a_size = a->mv_size - (aptr - (const char*)a->mv_data);
|
||||
const ssize_t b_size = b->mv_size - (bptr - (const char*)b->mv_data);
|
||||
|
||||
unsigned int len = a_size;
|
||||
ssize_t len_diff = (ssize_t) a_size - (ssize_t) b_size;
|
||||
if (len_diff > 0)
|
||||
{
|
||||
len = b_size;
|
||||
len_diff = 1;
|
||||
}
|
||||
|
||||
int diff = memcmp(aptr, bptr, len);
|
||||
return diff ? diff : len_diff<0 ? -1 : len_diff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -229,6 +278,7 @@ namespace
|
||||
* cc_trade_used nonce uint64_t
|
||||
* cc_orders nonce {order metadata}
|
||||
* cc_shares city/height {share metadata}
|
||||
* cc_events height account/flag/string
|
||||
*
|
||||
* Note: where the data items are of uniform size, DUPFIXED tables have
|
||||
* been used to save space. In most of these cases, a dummy "zerokval"
|
||||
@ -271,6 +321,7 @@ const char* const LMDB_CC_USED_NONCES = "cc_used_nonces";
|
||||
const char* const LMDB_CC_TRADE_USED = "cc_trade_used";
|
||||
const char* const LMDB_CC_ORDERS = "cc_orders";
|
||||
const char* const LMDB_CC_SHARES = "cc_shares";
|
||||
const char* const LMDB_CC_EVENTS = "cc_events";
|
||||
|
||||
const char* const LMDB_PROPERTIES = "properties";
|
||||
|
||||
@ -447,6 +498,12 @@ typedef struct mdb_order_t
|
||||
uint64_t expiration;
|
||||
} mdb_order_t;
|
||||
|
||||
struct cc_events_data_t
|
||||
{
|
||||
uint32_t account;
|
||||
uint32_t flag;
|
||||
};
|
||||
|
||||
std::atomic<uint64_t> mdb_txn_safe::num_active_txns{0};
|
||||
std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT;
|
||||
|
||||
@ -1527,6 +1584,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
lmdb_db_open(txn, LMDB_CC_TRADE_USED, MDB_INTEGERKEY | MDB_CREATE, m_cc_trade_used, "Failed to open db handle for m_cc_trade_used");
|
||||
lmdb_db_open(txn, LMDB_CC_ORDERS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_cc_orders, "Failed to open db handle for m_cc_orders");
|
||||
lmdb_db_open(txn, LMDB_CC_SHARES, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_cc_shares, "Failed to open db handle for m_cc_shares");
|
||||
lmdb_db_open(txn, LMDB_CC_EVENTS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT, m_cc_events, "Failed to open db handle for m_cc_events");
|
||||
|
||||
lmdb_db_open(txn, LMDB_PROPERTIES, MDB_CREATE, m_properties, "Failed to open db handle for m_properties");
|
||||
|
||||
@ -1555,6 +1613,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
mdb_set_dupsort(txn, m_cc_trade_used, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_cc_orders, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_cc_shares, compare_uint32_uint64);
|
||||
mdb_set_compare(txn, m_cc_events, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_cc_events, compare_events);
|
||||
|
||||
if (!(mdb_flags & MDB_RDONLY))
|
||||
{
|
||||
@ -1745,6 +1805,8 @@ void BlockchainLMDB::reset()
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_orders: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_cc_shares, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_shares: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_cc_events, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_events: ", result).c_str()));
|
||||
|
||||
// init with current version
|
||||
MDB_val_str(k, "version");
|
||||
@ -5964,6 +6026,134 @@ bool BlockchainLMDB::get_cc_shares(uint32_t city, uint64_t height, cc_shares_dat
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::add_cc_events(uint64_t height, const std::vector<cc::game_update_event_t> &events)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
mdb_txn_cursors *m_cursors = &m_wcursors;
|
||||
|
||||
CURSOR(cc_events)
|
||||
|
||||
for (const auto &e: events)
|
||||
{
|
||||
cc_events_data_t *data = (cc_events_data_t*)alloca(sizeof(cc_events_data_t) + e.event.size());
|
||||
data->account = e.account;
|
||||
data->flag = e.flag;
|
||||
memcpy(data + 1, e.event.data(), e.event.size());
|
||||
|
||||
MDB_val k = {sizeof(uint64_t), (void *)&height};
|
||||
MDB_val v[2] = {{sizeof(cc_events_data_t) + e.event.size(), (void *)data}, {em_account_flag_event, NULL}};
|
||||
if (auto result = mdb_cursor_put(m_cur_cc_events, &k, v, 0)) {
|
||||
throw0(DB_ERROR(lmdb_error("Error adding event data to db transaction: ", result).c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlockchainLMDB::remove_cc_events(uint64_t height)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
mdb_txn_cursors *m_cursors = &m_wcursors;
|
||||
|
||||
CURSOR(cc_events)
|
||||
|
||||
MDB_val k = {sizeof(height), (void*)&height}, v;
|
||||
int result = mdb_cursor_get(m_cur_cc_events, &k, &v, MDB_SET);
|
||||
if (result == MDB_NOTFOUND)
|
||||
return;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error getting events data from db: ", result).c_str()));
|
||||
mdb_size_t count;
|
||||
result = mdb_cursor_count(m_cur_cc_events, &count);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error counting events data from db: ", result).c_str()));
|
||||
MDEBUG("deleting " << count << " events at height " << height);
|
||||
result = mdb_cursor_del(m_cur_cc_events, MDB_NODUPDATA);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error deleting events data from db: ", result).c_str()));
|
||||
}
|
||||
|
||||
bool BlockchainLMDB::get_cc_events(uint64_t height, uint32_t account, uint32_t flag, std::vector<cc::game_update_event_t> &events) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
events.clear();
|
||||
|
||||
// we can lookup by flag, but the search has to be hierarchical, so fill account in first
|
||||
if (flag > 0 && account == 0)
|
||||
{
|
||||
cc_flag_data_t cfd;
|
||||
if (!get_cc_flag_data(flag, cfd, NULL))
|
||||
{
|
||||
// flag does not exist
|
||||
return true;
|
||||
}
|
||||
account = cfd.owner;
|
||||
}
|
||||
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(cc_events)
|
||||
|
||||
const event_match_t match = flag ? em_account_flag : em_account;
|
||||
MDB_cursor_op op = (account || flag) ? MDB_GET_BOTH : MDB_SET;
|
||||
|
||||
cc_events_data_t ed{account, flag};
|
||||
MDB_val k = {sizeof(uint64_t), (void*)&height};
|
||||
MDB_val v[2] = {{sizeof(ed), (void*)&ed}, {match, NULL}};
|
||||
int result = mdb_cursor_get(m_cur_cc_events, &k, v, op);
|
||||
if (result == MDB_NOTFOUND)
|
||||
return true;
|
||||
if (result)
|
||||
{
|
||||
MERROR("Events data not found for height " << height << ", account " << account << ", flag " << flag << ": " << mdb_strerror(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the first record since we can end up in the middle :/
|
||||
while (1)
|
||||
{
|
||||
MDB_val k2, v2;
|
||||
result = mdb_cursor_get(m_cur_cc_events, &k2, &v2, MDB_PREV_DUP);
|
||||
if (result == MDB_NOTFOUND)
|
||||
break;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error getting event: ", result).c_str()));
|
||||
const cc_events_data_t *ed = (const cc_events_data_t*)v2.mv_data;
|
||||
const bool match = (account == 0 || account == ed->account) && (flag == 0 || flag == ed->flag);
|
||||
if (!match)
|
||||
{
|
||||
result = mdb_cursor_get(m_cur_cc_events, &k2, &v2, MDB_NEXT_DUP);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error getting event: ", result).c_str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// walk till the first non matching record
|
||||
while (1)
|
||||
{
|
||||
MDB_val k2, v2;
|
||||
result = mdb_cursor_get(m_cur_cc_events, &k2, &v2, MDB_GET_CURRENT);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error getting event: ", result).c_str()));
|
||||
const cc_events_data_t *ed = (const cc_events_data_t*)v2.mv_data;
|
||||
const bool match = (account == 0 || account == ed->account) && (flag == 0 || flag == ed->flag);
|
||||
if (!match)
|
||||
break;
|
||||
events.push_back({ed->account, ed->flag, std::string((const char*)(ed+1), v2.mv_size - sizeof(cc_events_data_t))});
|
||||
result = mdb_cursor_get(m_cur_cc_events, &k2, &v2, MDB_NEXT_DUP);
|
||||
if (result == MDB_NOTFOUND)
|
||||
break;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Error getting event: ", result).c_str()));
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t BlockchainLMDB::get_database_size() const
|
||||
{
|
||||
uint64_t size = 0;
|
||||
|
@ -82,6 +82,7 @@ typedef struct mdb_txn_cursors
|
||||
MDB_cursor *m_txc_cc_trade_used;
|
||||
MDB_cursor *m_txc_cc_orders;
|
||||
MDB_cursor *m_txc_cc_shares;
|
||||
MDB_cursor *m_txc_cc_events;
|
||||
} mdb_txn_cursors;
|
||||
|
||||
#define m_cur_blocks m_cursors->m_txc_blocks
|
||||
@ -111,6 +112,7 @@ typedef struct mdb_txn_cursors
|
||||
#define m_cur_cc_trade_used m_cursors->m_txc_cc_trade_used
|
||||
#define m_cur_cc_orders m_cursors->m_txc_cc_orders
|
||||
#define m_cur_cc_shares m_cursors->m_txc_cc_shares
|
||||
#define m_cur_cc_events m_cursors->m_txc_cc_events
|
||||
|
||||
typedef struct mdb_rflags
|
||||
{
|
||||
@ -142,6 +144,7 @@ typedef struct mdb_rflags
|
||||
bool m_rf_cc_trade_used;
|
||||
bool m_rf_cc_orders;
|
||||
bool m_rf_cc_shares;
|
||||
bool m_rf_cc_events;
|
||||
} mdb_rflags;
|
||||
|
||||
typedef struct mdb_threadinfo
|
||||
@ -384,6 +387,7 @@ public:
|
||||
static int compare_hash32(const MDB_val *a, const MDB_val *b);
|
||||
static int compare_uint32_uint64(const MDB_val *a, const MDB_val *b);
|
||||
static int compare_string(const MDB_val *a, const MDB_val *b);
|
||||
static int compare_events(const MDB_val *a, const MDB_val *b);
|
||||
|
||||
private:
|
||||
void do_resize(uint64_t size_increase=0);
|
||||
@ -500,6 +504,10 @@ private:
|
||||
void remove_cc_shares(uint32_t city, uint64_t height);
|
||||
bool get_cc_shares(uint32_t city, uint64_t height, cc_shares_data_t &sd) const;
|
||||
|
||||
void add_cc_events(uint64_t height, const std::vector<cc::game_update_event_t> &events);
|
||||
void remove_cc_events(uint64_t height);
|
||||
bool get_cc_events(uint64_t height, uint32_t account, uint32_t flag, std::vector<cc::game_update_event_t> &events) const;
|
||||
|
||||
// fix up anything that may be wrong due to past bugs
|
||||
virtual void fixup();
|
||||
|
||||
@ -562,6 +570,7 @@ private:
|
||||
MDB_dbi m_cc_trade_used;
|
||||
MDB_dbi m_cc_orders;
|
||||
MDB_dbi m_cc_shares;
|
||||
MDB_dbi m_cc_events;
|
||||
|
||||
mutable uint64_t m_cum_size; // used in batch size estimation
|
||||
mutable unsigned int m_cum_count;
|
||||
|
@ -215,6 +215,10 @@ public:
|
||||
virtual void remove_cc_shares(uint32_t city, uint64_t height) {}
|
||||
virtual bool get_cc_shares(uint32_t city, uint64_t height, cc_shares_data_t &sd) const { return false; }
|
||||
|
||||
virtual void add_cc_events(uint64_t height, const std::vector<cc::game_update_event_t> &events) {}
|
||||
virtual void remove_cc_events(uint64_t height) {}
|
||||
virtual bool get_cc_events(uint64_t height, uint32_t account, uint32_t flag, std::vector<cc::game_update_event_t> &events) const { return false; }
|
||||
|
||||
private:
|
||||
uint32_t n_accounts;
|
||||
};
|
||||
|
@ -41,7 +41,7 @@
|
||||
namespace cc
|
||||
{
|
||||
|
||||
cc::game_update_events_t cc_command_handler_game_update::events = {};
|
||||
cc::game_update_events_t cc_command_handler_game_update::last_events = {};
|
||||
|
||||
cc_command_handler_game_update cc_command_handler_game_update::instance;
|
||||
|
||||
@ -100,7 +100,7 @@ bool cc_command_handler_game_update::check(const cryptonote::BlockchainDB &db, c
|
||||
}
|
||||
}
|
||||
|
||||
events = std::move(new_events);
|
||||
last_events = std::move(new_events);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -184,6 +184,7 @@ bool cc_command_handler_game_update::execute(cryptonote::BlockchainDB &db, const
|
||||
if (!execute_city(db, game.cities[i]))
|
||||
return false;
|
||||
}
|
||||
db.add_cc_events(db.height() - 1, last_events);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -273,15 +274,15 @@ bool cc_command_handler_game_update::revert(cryptonote::BlockchainDB &db, const
|
||||
{
|
||||
const cryptonote::cc_command_game_update_t &game = boost::get<cryptonote::cc_command_game_update_t>(cmd);
|
||||
|
||||
db.remove_cc_events(db.height() - 1);
|
||||
|
||||
for (size_t i = 0; i < game.cities.size(); ++i)
|
||||
{
|
||||
if (!revert_city(db, game.cities[game.cities.size() - 1 - i]))
|
||||
const cryptonote::cc_command_game_update_t::city_t &city = game.cities[game.cities.size() - 1 - i];
|
||||
if (!revert_city(db, city))
|
||||
return false;
|
||||
}
|
||||
|
||||
// technically we should fill up with previous game update's events, but no way to easily do that
|
||||
events.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ public:
|
||||
|
||||
static cc_command_handler_game_update instance;
|
||||
|
||||
static cc::game_update_events_t events;
|
||||
private:
|
||||
static cc::game_update_events_t last_events;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ namespace cryptonote
|
||||
return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()});
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_game_update_block(uint64_t height, const crypto::hash &prev_hash)
|
||||
bool is_game_update_block(uint64_t height)
|
||||
{
|
||||
return height % GAME_UPDATE_FREQUENCY == GAME_UPDATE_FREQUENCY-1;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace cryptonote
|
||||
bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx);
|
||||
bool is_v1_tx(const blobdata_ref& tx_blob);
|
||||
bool is_v1_tx(const blobdata& tx_blob);
|
||||
bool is_game_update_block(uint64_t height, const crypto::hash &prev_hash);
|
||||
bool is_game_update_block(uint64_t height);
|
||||
|
||||
template<typename T>
|
||||
bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field, size_t index = 0)
|
||||
|
@ -1184,7 +1184,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height,
|
||||
if (b.miner_tx.version == 2)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.extra.size() <= 256, false, "v2 coinbase extra is too large");
|
||||
const bool is_update = b.major_version >= 12 && cryptonote::is_game_update_block(height, b.prev_id);
|
||||
const bool is_update = b.major_version >= 12 && cryptonote::is_game_update_block(height);
|
||||
CHECK_AND_ASSERT_MES((b.miner_tx.minor_version > 0) == is_update, false, "Update block does not match minor version");
|
||||
if (b.miner_tx.minor_version == 0)
|
||||
{
|
||||
@ -1279,7 +1279,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
base_reward = 0;
|
||||
}
|
||||
|
||||
const bool is_game_update = version >= 12 && cryptonote::is_game_update_block(cryptonote::get_block_height(b), get_tail_id());
|
||||
const bool is_game_update = version >= 12 && cryptonote::is_game_update_block(cryptonote::get_block_height(b));
|
||||
if (is_game_update)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.cc_cmd.type() == typeid(cryptonote::cc_command_game_update_t), false, "Game update command has wrong type");
|
||||
@ -1556,7 +1556,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
uint8_t hf_version = b.major_version;
|
||||
size_t max_outs = hf_version >= 4 ? 1 : 11;
|
||||
cryptonote::cc_command_t cc_cmd;
|
||||
const bool is_game_update = hf_version >= 12 && cryptonote::is_game_update_block(height, get_tail_id());
|
||||
const bool is_game_update = hf_version >= 12 && cryptonote::is_game_update_block(height);
|
||||
if (is_game_update)
|
||||
{
|
||||
cc_cmd = cc::create_cc_game_update_command(*m_db, false);
|
||||
|
@ -3728,6 +3728,8 @@ namespace cryptonote
|
||||
++flag_id;
|
||||
}
|
||||
|
||||
res.top_hash = db.top_block_hash(&res.height);
|
||||
|
||||
cryptonote::cc_shares_data_t sd;
|
||||
if (!db.get_cc_shares(req.city, db.height() - 1, sd))
|
||||
{
|
||||
@ -3740,15 +3742,21 @@ namespace cryptonote
|
||||
res.snapshot.shares.push_back({(uint8_t)role, sd.payout[role], sd.shares[role]});
|
||||
}
|
||||
|
||||
const auto &events = cc::cc_command_handler_game_update::events;
|
||||
res.snapshot.last_update_events.reserve(events.size());
|
||||
std::vector<cc::game_update_event_t> events;
|
||||
uint64_t height = res.height;
|
||||
while (height > 0 && !cryptonote::is_game_update_block(height))
|
||||
--height;
|
||||
if (!db.get_cc_events(height, 0, 0, events))
|
||||
{
|
||||
res.status = "Internal error: can't get events data";
|
||||
MERROR(res.status);
|
||||
return false;
|
||||
}
|
||||
for (const auto &e: events)
|
||||
{
|
||||
res.snapshot.last_update_events.push_back({e.account, e.flag, e.event});
|
||||
}
|
||||
|
||||
res.top_hash = db.top_block_hash(&res.height);
|
||||
|
||||
block blk;
|
||||
bool orphan = false;
|
||||
bool have_block = m_core.get_block_by_hash(res.top_hash, blk, &orphan);
|
||||
@ -3919,15 +3927,26 @@ namespace cryptonote
|
||||
|
||||
try
|
||||
{
|
||||
res.events.reserve(cc::cc_command_handler_game_update::events.size());
|
||||
for (const auto &e: cc::cc_command_handler_game_update::events)
|
||||
{
|
||||
res.events.push_back({e.account, e.flag, e.event});
|
||||
}
|
||||
crypto::hash top_hash;
|
||||
m_core.get_blockchain_top(res.height, top_hash);
|
||||
++res.height; // turn top block height into blockchain height
|
||||
res.top_hash = epee::string_tools::pod_to_hex(top_hash);
|
||||
|
||||
BlockchainDB &db = m_core.get_blockchain_storage().get_db();
|
||||
std::vector<cc::game_update_event_t> events;
|
||||
uint64_t height = res.height;
|
||||
while (height > 0 && !cryptonote::is_game_update_block(height))
|
||||
--height;
|
||||
if (!db.get_cc_events(height, 0, 0, events))
|
||||
{
|
||||
res.status = "Internal error: can't get events data";
|
||||
MERROR(res.status);
|
||||
return false;
|
||||
}
|
||||
for (const auto &e: events)
|
||||
{
|
||||
res.events.push_back({e.account, e.flag, e.event});
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
@ -532,7 +532,7 @@ bool gen_cc_tx_validation_base::generate_with_full(std::vector<test_event_entry>
|
||||
12, 12, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
|
||||
crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 12),
|
||||
false, "Failed to generate block");
|
||||
if (cryptonote::is_game_update_block(cryptonote::get_block_height(blk), blk.prev_id))
|
||||
if (cryptonote::is_game_update_block(cryptonote::get_block_height(blk)))
|
||||
{
|
||||
blk.miner_tx.minor_version = 1;
|
||||
DO_CALLBACK(events, "generate_game_update_command");
|
||||
@ -540,7 +540,7 @@ bool gen_cc_tx_validation_base::generate_with_full(std::vector<test_event_entry>
|
||||
events.push_back(blk);
|
||||
blk_last = blk;
|
||||
blockchain.push_back(blk);
|
||||
if (cryptonote::is_game_update_block(cryptonote::get_block_height(blk), blk.prev_id))
|
||||
if (cryptonote::is_game_update_block(cryptonote::get_block_height(blk)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2256,3 +2256,102 @@ TEST(cc_influence, roles)
|
||||
ASSERT_EQ(100, cc::calculate_influence(ROLE_RESIDENTIAL1, std::vector<uint32_t>{0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0}.data(), 0, 0, events));
|
||||
ASSERT_EQ( 90, cc::calculate_influence(ROLE_RESIDENTIAL1, std::vector<uint32_t>{0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0}.data(), 0, 0, events));
|
||||
}
|
||||
|
||||
TEST(cc, events)
|
||||
{
|
||||
cryptonote::BlockchainDB *db = cryptonote::new_db();
|
||||
ASSERT_TRUE(db);
|
||||
|
||||
boost::filesystem::path path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
const std::string filename = (path / db->get_db_name()).string();
|
||||
db->open(filename, 0);
|
||||
|
||||
cryptonote::db_wtxn_guard guard(db);
|
||||
|
||||
// starts off empty
|
||||
std::vector<cc::game_update_event_t> events;
|
||||
ASSERT_TRUE(db->get_cc_events(0, 0, 0, events));
|
||||
ASSERT_TRUE(events.empty());
|
||||
|
||||
// can delete nothing
|
||||
db->remove_cc_events(7434);
|
||||
ASSERT_TRUE(db->get_cc_events(0, 0, 0, events));
|
||||
ASSERT_TRUE(events.empty());
|
||||
|
||||
// add a couple at height 127
|
||||
db->add_cc_events(127, {{4, 1, "building 1"}, {4, 0, "no building"}});
|
||||
ASSERT_TRUE(db->get_cc_events(127, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 2);
|
||||
|
||||
// add a bundle at 200
|
||||
db->add_cc_events(200, {
|
||||
{2, 0, "account 2"},
|
||||
{4, 1, "account 4, building 1, event 0"},
|
||||
{5, 2, "account 5, building 2, event 0"},
|
||||
{4, 1, "account 4, building 1, event 1"},
|
||||
{4, 1, "account 4, building 1, event 2"},
|
||||
{5, 3, "account 5, building 3, event 0"},
|
||||
{6, 4, "account 6, building 4, event 0"},
|
||||
{4, 5, "account 4, building 5, event 0"},
|
||||
{4, 0, "account 4"},
|
||||
{1, 0, "account 1"}
|
||||
});
|
||||
ASSERT_TRUE(db->get_cc_events(200, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 10);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 4, 0, events));
|
||||
ASSERT_EQ(events.size(), 5);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 5, 0, events));
|
||||
ASSERT_EQ(events.size(), 2);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 6, 0, events));
|
||||
ASSERT_EQ(events.size(), 1);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 7, 6, events));
|
||||
ASSERT_EQ(events.size(), 0);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 8, 0, events));
|
||||
ASSERT_EQ(events.size(), 0);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 4, 4, events));
|
||||
ASSERT_EQ(events.size(), 0);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 4, 1, events));
|
||||
ASSERT_EQ(events.size(), 3);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 4, 5, events));
|
||||
ASSERT_EQ(events.size(), 1);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 5, 1, events));
|
||||
ASSERT_EQ(events.size(), 0);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 1, 0, events));
|
||||
ASSERT_EQ(events.size(), 1);
|
||||
|
||||
// 127 still exists, unchanged
|
||||
ASSERT_TRUE(db->get_cc_events(127, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 2);
|
||||
|
||||
// add at 240
|
||||
db->add_cc_events(240, {{4, 1, "building 1"}, {4, 0, "no building"}});
|
||||
ASSERT_TRUE(db->get_cc_events(240, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 2);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 10);
|
||||
|
||||
// delete 200
|
||||
db->remove_cc_events(200);
|
||||
ASSERT_TRUE(db->get_cc_events(240, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 2);
|
||||
ASSERT_TRUE(db->get_cc_events(200, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 0);
|
||||
ASSERT_TRUE(db->get_cc_events(127, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 2);
|
||||
|
||||
// we can add 200 back
|
||||
db->add_cc_events(200, {
|
||||
{2, 0, "account 2"},
|
||||
{4, 1, "account 4, building 1, event 0"},
|
||||
{5, 2, "account 5, building 2, event 0"},
|
||||
{4, 1, "account 4, building 1, event 1"},
|
||||
{4, 1, "account 4, building 1, event 2"},
|
||||
{5, 3, "account 5, building 3, event 0"},
|
||||
{6, 4, "account 6, building 4, event 0"},
|
||||
{4, 5, "account 4, building 5, event 0"},
|
||||
{4, 0, "account 4"},
|
||||
{1, 0, "account 1"}
|
||||
});
|
||||
ASSERT_TRUE(db->get_cc_events(200, 0, 0, events));
|
||||
ASSERT_EQ(events.size(), 10);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user