townforge/tests/db_tests/db_tests_cc.cpp
2024-11-17 16:33:07 +00:00

1451 lines
55 KiB
C++

// Copyright (c) 2020, Crypto City
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "blockchain_db/blockchain_db.h"
#include "cc/cc.h"
#include "cc/cc_script.h"
#include "cc/coru.h"
#include "db_tests.h"
bool db_tests_cc_blobs(cryptonote::BlockchainDB &db)
{
const crypto::hash hash = cc::script::get_blob_hash("test");
size_t n_blobs;
cryptonote::blobdata blob;
n_blobs = 0;
DB_TESTS_ASSERT(db.for_all_cc_blobs([&n_blobs](const crypto::hash&, uint32_t, const cryptonote::blobdata_ref&) { ++n_blobs; return true; }));
DB_TESTS_ASSERT(n_blobs == 0);
DB_TESTS_ASSERT(db.get_cc_blob(hash, blob) == 0);
db.add_cc_blob("test");
n_blobs = 0;
DB_TESTS_ASSERT(db.for_all_cc_blobs([&n_blobs, &hash](const crypto::hash &h, uint32_t refs, const cryptonote::blobdata_ref &blob) {
DB_TESTS_ASSERT(h == hash);
DB_TESTS_ASSERT(refs == 1);
DB_TESTS_ASSERT(blob == "test");
++n_blobs;
return true;
}));
DB_TESTS_ASSERT(n_blobs == 1);
DB_TESTS_ASSERT(db.get_cc_blob(hash, blob) == 1);
DB_TESTS_ASSERT(blob == "test");
db.add_cc_blob("test");
n_blobs = 0;
DB_TESTS_ASSERT(db.for_all_cc_blobs([&n_blobs, &hash](const crypto::hash &h, uint32_t refs, const cryptonote::blobdata_ref &blob) {
DB_TESTS_ASSERT(h == hash);
DB_TESTS_ASSERT(refs == 2);
DB_TESTS_ASSERT(blob == "test");
++n_blobs;
return true;
}));
DB_TESTS_ASSERT(n_blobs == 1);
DB_TESTS_ASSERT(db.get_cc_blob(hash, blob) == 2);
DB_TESTS_ASSERT(blob == "test");
db.delete_cc_blob("test");
n_blobs = 0;
DB_TESTS_ASSERT(db.for_all_cc_blobs([&n_blobs, &hash](const crypto::hash &h, uint32_t refs, const cryptonote::blobdata_ref &blob) {
DB_TESTS_ASSERT(h == hash);
DB_TESTS_ASSERT(refs == 1);
DB_TESTS_ASSERT(blob == "test");
++n_blobs;
return true;
}));
DB_TESTS_ASSERT(n_blobs == 1);
DB_TESTS_ASSERT(db.get_cc_blob(hash, blob) == 1);
DB_TESTS_ASSERT(blob == "test");
db.delete_cc_blob("test");
n_blobs = 0;
DB_TESTS_ASSERT(db.for_all_cc_blobs([&n_blobs](const crypto::hash&, uint32_t, const cryptonote::blobdata_ref&) { ++n_blobs; return true; }));
DB_TESTS_ASSERT(n_blobs == 0);
DB_TESTS_ASSERT(db.get_cc_blob(hash, blob) == 0);
return true;
}
bool db_tests_cc_random_seed(cryptonote::BlockchainDB &db)
{
db.set_cc_random_seed(crypto::null_hash);
DB_TESTS_ASSERT(db.get_cc_random_seed() == crypto::null_hash);
crypto::hash seed = crypto::null_hash;
seed.data[3] = 0x42;
db.set_cc_random_seed(seed);
DB_TESTS_ASSERT(db.get_cc_random_seed() == seed);
return true;
}
bool db_tests_cc_foreclosures(cryptonote::BlockchainDB &db)
{
size_t n_mortgages = 0;
DB_TESTS_ASSERT(db.for_all_cc_foreclosures([&n_mortgages](const cc::foreclosure_t&) {
++n_mortgages;
return true;
}));
DB_TESTS_ASSERT(n_mortgages == 0);
db.add_cc_foreclosure({10, 11, 12, 13});
n_mortgages = 0;
DB_TESTS_ASSERT(db.for_all_cc_foreclosures([&n_mortgages](const cc::foreclosure_t &foreclosure) {
DB_TESTS_ASSERT(foreclosure.mortgage == 10);
DB_TESTS_ASSERT(foreclosure.flag == 11);
DB_TESTS_ASSERT(foreclosure.height == 12);
DB_TESTS_ASSERT(foreclosure.debt_per_share == 13);
++n_mortgages;
return true;
}));
DB_TESTS_ASSERT(n_mortgages == 1);
db.remove_cc_foreclosure(10);
n_mortgages = 0;
DB_TESTS_ASSERT(db.for_all_cc_foreclosures([&n_mortgages](const cc::foreclosure_t&) {
++n_mortgages;
return true;
}));
DB_TESTS_ASSERT(n_mortgages == 0);
return true;
}
bool db_tests_cc_runestones(cryptonote::BlockchainDB &db)
{
size_t n_runestones = 0;
DB_TESTS_ASSERT(db.for_all_cc_runestones([&n_runestones](const cc::runestone_t &runestone) {
++n_runestones;
return true;
}));
DB_TESTS_ASSERT(n_runestones == 0);
cc::runestone_t runestone;
runestone.flag = 10;
runestone.x = 11;
runestone.y = 12;
runestone.h = 13;
runestone.script = 14;
runestone.message = "15";
runestone.overrides.push_back(std::make_tuple(0, 1, "foo"));
runestone.overrides.push_back(std::make_tuple(1, 2, "bar"));
db.add_cc_runestone(runestone);
n_runestones = 0;
DB_TESTS_ASSERT(db.for_all_cc_runestones([&n_runestones](const cc::runestone_t &runestone) {
DB_TESTS_ASSERT(runestone.flag == 10);
DB_TESTS_ASSERT(runestone.x == 11);
DB_TESTS_ASSERT(runestone.y == 12);
DB_TESTS_ASSERT(runestone.h == 13);
DB_TESTS_ASSERT(runestone.script == 14);
DB_TESTS_ASSERT(runestone.message == "15");
DB_TESTS_ASSERT(runestone.overrides.size() == 2);
DB_TESTS_ASSERT(runestone.overrides[0] == std::make_tuple(0, 1, "foo"));
DB_TESTS_ASSERT(runestone.overrides[1] == std::make_tuple(1, 2, "bar"));
++n_runestones;
return true;
}));
DB_TESTS_ASSERT(n_runestones == 1);
cc::runestone_t r;
DB_TESTS_ASSERT(!db.get_cc_runestone(10, 0, 0, 0, r));
DB_TESTS_ASSERT(db.get_cc_runestone(10, 11, 12, 13, r));
DB_TESTS_ASSERT(r.flag == 10);
DB_TESTS_ASSERT(r.x == 11);
DB_TESTS_ASSERT(r.y == 12);
DB_TESTS_ASSERT(r.h == 13);
DB_TESTS_ASSERT(r.script == 14);
DB_TESTS_ASSERT(r.message == "15");
DB_TESTS_ASSERT(r.overrides.size() == 2);
DB_TESTS_ASSERT(r.overrides[0] == std::make_tuple(0, 1, "foo"));
DB_TESTS_ASSERT(r.overrides[1] == std::make_tuple(1, 2, "bar"));
db.remove_cc_runestone(10, 11, 12, 13);
n_runestones = 0;
DB_TESTS_ASSERT(db.for_all_cc_runestones([&n_runestones](const cc::runestone_t &runestone) {
++n_runestones;
return true;
}));
DB_TESTS_ASSERT(n_runestones == 0);
return true;
}
bool db_tests_cc_script_variables(cryptonote::BlockchainDB &db)
{
size_t n_script_variables = 0;
DB_TESTS_ASSERT(db.for_all_cc_script_variables([&n_script_variables](const boost::string_ref&, uint64_t) { ++n_script_variables; return true; }));
DB_TESTS_ASSERT(n_script_variables == 0);
DB_TESTS_ASSERT(db.get_cc_script_variable("test") == 0);
db.set_cc_script_variable("test", 1);
DB_TESTS_ASSERT(db.get_cc_script_variable("test") == 1);
n_script_variables = 0;
DB_TESTS_ASSERT(db.for_all_cc_script_variables([&n_script_variables](const boost::string_ref &name, uint64_t value) {
DB_TESTS_ASSERT(name == "test");
DB_TESTS_ASSERT(value == 1);
++n_script_variables;
return true;
}));
DB_TESTS_ASSERT(n_script_variables == 1);
db.set_cc_script_variable("test", 0);
DB_TESTS_ASSERT(db.get_cc_script_variable("test") == 0);
n_script_variables = 0;
DB_TESTS_ASSERT(db.for_all_cc_script_variables([&n_script_variables](const boost::string_ref&, uint64_t) { ++n_script_variables; return true; }));
DB_TESTS_ASSERT(n_script_variables == 0);
return true;
}
bool db_tests_cc_scripts(cryptonote::BlockchainDB &db)
{
size_t n_scripts = 0;
DB_TESTS_ASSERT(db.for_all_cc_scripts([&n_scripts](const cryptonote::cc_script_data_t&){ ++n_scripts; return true; }));
DB_TESTS_ASSERT(n_scripts == 0);
DB_TESTS_ASSERT(db.get_num_cc_scripts() == 0);
const uint32_t id = db.allocate_new_cc_script("name", "icon", "desc", "group", "blob", false, 42, true, false);
DB_TESTS_ASSERT(id != 0);
DB_TESTS_ASSERT(db.get_num_cc_scripts() == 1);
n_scripts = 0;
DB_TESTS_ASSERT(db.for_all_cc_scripts([&n_scripts, id](const cryptonote::cc_script_data_t &s){
DB_TESTS_ASSERT(s.id == id);
DB_TESTS_ASSERT(s.name == "name");
DB_TESTS_ASSERT(s.desc == "desc");
DB_TESTS_ASSERT(s.icon == "icon");
DB_TESTS_ASSERT(s.blob == "blob");
DB_TESTS_ASSERT(s.group == "group");
DB_TESTS_ASSERT(s.owner == 42);
DB_TESTS_ASSERT(s.is_public == true);
DB_TESTS_ASSERT(s.enabled == true);
DB_TESTS_ASSERT(s.is_storyline == false);
++n_scripts;
return true;
}));
DB_TESTS_ASSERT(n_scripts == 1);
const uint32_t id2 = db.allocate_new_cc_script("name2", "icon2", "desc2", "group2", "blob2", false, 43, false, true);
DB_TESTS_ASSERT(id2 && id2 == id + 1);
n_scripts = 0;
DB_TESTS_ASSERT(db.for_all_cc_scripts([&n_scripts, id](const cryptonote::cc_script_data_t &s){
DB_TESTS_ASSERT(s.id == id || s.id == id + 1);
DB_TESTS_ASSERT(s.name == (s.id == id ? "name" : "name2"));
DB_TESTS_ASSERT(s.desc == (s.id == id ? "desc" : "desc2"));
DB_TESTS_ASSERT(s.icon == (s.id == id ? "icon" : "icon2"));
DB_TESTS_ASSERT(s.blob == (s.id == id ? "blob" : "blob2"));
DB_TESTS_ASSERT(s.group == (s.id == id ? "group" : "group2"));
DB_TESTS_ASSERT(s.owner == (s.id == id ? 42 : 43));
DB_TESTS_ASSERT(s.is_public == (s.id == id));
DB_TESTS_ASSERT(s.enabled);
DB_TESTS_ASSERT(s.is_storyline == (s.id != id));
++n_scripts;
return true;
}));
DB_TESTS_ASSERT(n_scripts == 2);
DB_TESTS_ASSERT(db.get_num_cc_scripts() == 2);
cryptonote::cc_script_data_t sd;
DB_TESTS_ASSERT(db.get_cc_script_data(id, sd));
DB_TESTS_ASSERT(sd.id == id);
DB_TESTS_ASSERT(sd.name == "name");
DB_TESTS_ASSERT(db.get_cc_script_data(id2, sd));
DB_TESTS_ASSERT(sd.id == id2);
DB_TESTS_ASSERT(sd.name == "name2");
db.set_cc_script_enabled(id, false);
n_scripts = 0;
DB_TESTS_ASSERT(db.for_all_cc_scripts([&n_scripts, id](const cryptonote::cc_script_data_t &s){
DB_TESTS_ASSERT(s.enabled == (s.id != id));
++n_scripts;
return true;
}));
DB_TESTS_ASSERT(n_scripts == 2);
db.set_cc_script_enabled(id, true);
n_scripts = 0;
DB_TESTS_ASSERT(db.for_all_cc_scripts([&n_scripts, id](const cryptonote::cc_script_data_t &s){
DB_TESTS_ASSERT(s.enabled == true);
++n_scripts;
return true;
}));
DB_TESTS_ASSERT(n_scripts == 2);
db.delete_cc_script(id2);
n_scripts = 0;
DB_TESTS_ASSERT(db.for_all_cc_scripts([&n_scripts, id](const cryptonote::cc_script_data_t &s){
DB_TESTS_ASSERT(s.id == id);
DB_TESTS_ASSERT(s.name == "name");
DB_TESTS_ASSERT(s.desc == "desc");
DB_TESTS_ASSERT(s.icon == "icon");
DB_TESTS_ASSERT(s.blob == "blob");
DB_TESTS_ASSERT(s.owner == 42);
DB_TESTS_ASSERT(s.is_public == true);
++n_scripts;
return true;
}));
DB_TESTS_ASSERT(n_scripts == 1);
DB_TESTS_ASSERT(db.get_num_cc_scripts() == 1);
return true;
}
bool db_tests_cc_script_effects(cryptonote::BlockchainDB &db)
{
cc::script::script_effects_t effects;
DB_TESTS_EXCEPTION(db.get_last_cc_script_effects(effects));
cc::script::script_effects_t test_effects;
test_effects.balances.push_back({3, 4, 5});
test_effects.local_variables.push_back({"test", 6});
db.add_cc_script_effects(test_effects);
db.get_last_cc_script_effects(effects);
DB_TESTS_ASSERT(effects.balances.size() == 1 && effects.balances[0].account == 3 && effects.balances[0].counterparty == 4 && effects.balances[0].balance_delta == 5);
DB_TESTS_ASSERT(effects.local_variables.size() == 1 && effects.local_variables[0].name == "test" && effects.local_variables[0].value_delta == 6);
db.add_cc_script_effects(test_effects);
db.get_last_cc_script_effects(effects);
DB_TESTS_ASSERT(effects.balances.size() == 1 && effects.balances[0].account == 3 && effects.balances[0].counterparty == 4 && effects.balances[0].balance_delta == 5);
DB_TESTS_ASSERT(effects.local_variables.size() == 1 && effects.local_variables[0].name == "test" && effects.local_variables[0].value_delta == 6);
db.delete_last_cc_script_effects();
db.delete_last_cc_script_effects();
DB_TESTS_EXCEPTION(db.delete_last_cc_script_effects());
return true;
}
bool db_tests_cc_item_counts(cryptonote::BlockchainDB &db)
{
DB_TESTS_ASSERT(db.get_cc_item_count(1) == 0);
DB_TESTS_ASSERT(db.get_cc_item_count(2) == 0);
db.set_cc_item_count(1, 1);
db.set_cc_item_count(2, 2);
DB_TESTS_ASSERT(db.get_cc_item_count(1) == 1);
DB_TESTS_ASSERT(db.get_cc_item_count(2) == 2);
db.set_cc_item_count(1, 0);
db.set_cc_item_count(2, 0);
DB_TESTS_ASSERT(db.get_cc_item_count(1) == 0);
DB_TESTS_ASSERT(db.get_cc_item_count(2) == 0);
return true;
}
bool db_tests_cc_invitations(cryptonote::BlockchainDB &db)
{
crypto::public_key pkey0 = crypto::null_pkey, pkey1 = crypto::null_pkey;
pkey0.data[0] = 8;
pkey1.data[0] = 16;
DB_TESTS_ASSERT(!db.has_invitation(pkey0));
DB_TESTS_ASSERT(!db.has_invitation(pkey1));
db.add_invitation(pkey0);
DB_TESTS_ASSERT(db.has_invitation(pkey0));
DB_TESTS_ASSERT(!db.has_invitation(pkey1));
db.add_invitation(pkey1);
DB_TESTS_ASSERT(db.has_invitation(pkey0));
DB_TESTS_ASSERT(db.has_invitation(pkey1));
db.remove_invitation(pkey0);
DB_TESTS_ASSERT(!db.has_invitation(pkey0));
DB_TESTS_ASSERT(db.has_invitation(pkey1));
db.remove_invitation(pkey1);
DB_TESTS_ASSERT(!db.has_invitation(pkey0));
DB_TESTS_ASSERT(!db.has_invitation(pkey1));
return true;
}
bool db_tests_cc_attributes(cryptonote::BlockchainDB &db)
{
cryptonote::cc_attribute_data_t ad;
size_t n_attributes = 0;
DB_TESTS_ASSERT(db.for_all_cc_attributes([&n_attributes](const cryptonote::cc_attribute_data_t &ad){ ++n_attributes; return true; }));
DB_TESTS_ASSERT(n_attributes == 0);
DB_TESTS_ASSERT(!db.get_cc_attribute(0, ad));
DB_TESTS_ASSERT(!db.get_cc_attribute(1, ad));
DB_TESTS_EXCEPTION(db.delete_cc_attribute(0));
DB_TESTS_EXCEPTION(db.delete_cc_attribute(1));
const uint32_t id = db.allocate_new_cc_attribute("name", "desc");
DB_TESTS_ASSERT(id == 1);
n_attributes = 0;
DB_TESTS_ASSERT(db.for_all_cc_attributes([&n_attributes](const cryptonote::cc_attribute_data_t &ad){
DB_TESTS_ASSERT(ad.name == "name");
DB_TESTS_ASSERT(ad.description == "desc");
++n_attributes;
return true;
}));
DB_TESTS_ASSERT(n_attributes == 1);
DB_TESTS_ASSERT(!db.get_cc_attribute(0, ad));
DB_TESTS_ASSERT(db.get_cc_attribute(1, ad));
DB_TESTS_ASSERT(ad.name == "name");
DB_TESTS_ASSERT(ad.description == "desc");
db.delete_cc_attribute(id);
DB_TESTS_ASSERT(!db.get_cc_attribute(0, ad));
DB_TESTS_ASSERT(!db.get_cc_attribute(1, ad));
return true;
}
bool db_tests_cc_auctions(cryptonote::BlockchainDB &db)
{
cc::auction_t ad;
size_t n_auctions = 0;
DB_TESTS_ASSERT(db.for_all_cc_auctions([&n_auctions](const cc::auction_t &auction){ ++n_auctions; return true; }));
DB_TESTS_ASSERT(n_auctions == 0);
DB_TESTS_ASSERT(!db.get_cc_auction_data(0, ad));
DB_TESTS_ASSERT(!db.get_cc_auction_data(1, ad));
DB_TESTS_EXCEPTION(db.remove_cc_auction(0));
DB_TESTS_EXCEPTION(db.remove_cc_auction(1));
const uint32_t id = db.allocate_cc_auction(1, cc::auction_t::type_flag, {std::make_pair(1, 1)}, 2, true, 60, "a", "b", 0);
DB_TESTS_ASSERT(id == 1);
n_auctions = 0;
DB_TESTS_ASSERT(db.for_all_cc_auctions([&n_auctions](const cc::auction_t &ad){
DB_TESTS_ASSERT(ad.id == 1);
DB_TESTS_ASSERT(ad.seller == 1);
DB_TESTS_ASSERT(ad.type == cc::auction_t::type_flag);
DB_TESTS_ASSERT(ad.entries.size() == 1);
DB_TESTS_ASSERT(ad.entries[0].first == 1);
DB_TESTS_ASSERT(ad.entries[0].second == 1);
DB_TESTS_ASSERT(ad.reserve_price == 60);
DB_TESTS_ASSERT(ad.title == "a");
DB_TESTS_ASSERT(ad.description == "b");
DB_TESTS_ASSERT(ad.bids.empty());
++n_auctions;
return true;
}));
DB_TESTS_ASSERT(n_auctions == 1);
DB_TESTS_ASSERT(!db.get_cc_auction_data(0, ad));
DB_TESTS_ASSERT(db.get_cc_auction_data(1, ad));
DB_TESTS_ASSERT(ad.id == 1);
DB_TESTS_ASSERT(ad.seller == 1);
DB_TESTS_ASSERT(ad.type == cc::auction_t::type_flag);
DB_TESTS_ASSERT(ad.entries.size() == 1);
DB_TESTS_ASSERT(ad.entries[0].first == 1);
DB_TESTS_ASSERT(ad.entries[0].second == 1);
DB_TESTS_ASSERT(ad.bids.empty());
db.add_cc_auction_bid(1, 2, crypto::null_pkey, 200, 200);
DB_TESTS_ASSERT(db.get_cc_auction_data(1, ad));
DB_TESTS_ASSERT(ad.bids.size() == 1);
DB_TESTS_ASSERT(ad.bids[0] == std::make_tuple(2, crypto::null_pkey, 200, 200));
db.add_cc_auction_bid(1, 3, crypto::null_pkey, 400, 300);
DB_TESTS_ASSERT(db.get_cc_auction_data(1, ad));
DB_TESTS_ASSERT(ad.bids.size() == 2);
DB_TESTS_ASSERT(ad.bids[0] == std::make_tuple(2, crypto::null_pkey, 200, 200));
DB_TESTS_ASSERT(ad.bids[1] == std::make_tuple(3, crypto::null_pkey, 400, 300));
db.set_cc_auction_ended(1, true);
n_auctions = 0;
DB_TESTS_ASSERT(db.for_all_cc_auctions([&n_auctions](const cc::auction_t &auction){ ++n_auctions; return true; }));
DB_TESTS_ASSERT(n_auctions == 0);
DB_TESTS_ASSERT(!db.get_cc_auction_data(1, ad));
db.set_cc_auction_ended(1, false);
DB_TESTS_ASSERT(db.get_cc_auction_data(1, ad));
db.remove_last_cc_auction_bid(1);
db.remove_last_cc_auction_bid(1);
DB_TESTS_ASSERT(db.get_cc_auction_data(1, ad));
DB_TESTS_ASSERT(ad.bids.empty());
db.remove_cc_auction(1);
DB_TESTS_ASSERT(!db.get_cc_auction_data(0, ad));
DB_TESTS_ASSERT(!db.get_cc_auction_data(1, ad));
return true;
}
bool db_tests_cc_hunt(cryptonote::BlockchainDB &db)
{
uint32_t moose, bears;
DB_TESTS_EXCEPTION(db.get_last_cc_hunt(moose, bears));
DB_TESTS_EXCEPTION(db.remove_last_cc_hunt());
db.add_cc_hunt(123, 456);
db.get_last_cc_hunt(moose, bears);
DB_TESTS_ASSERT(moose == 123);
DB_TESTS_ASSERT(bears == 456);
db.add_cc_hunt(555, 888);
db.get_last_cc_hunt(moose, bears);
DB_TESTS_ASSERT(moose == 555);
DB_TESTS_ASSERT(bears == 888);
db.remove_last_cc_hunt();
db.get_last_cc_hunt(moose, bears);
DB_TESTS_ASSERT(moose == 123);
DB_TESTS_ASSERT(bears == 456);
db.remove_last_cc_hunt();
DB_TESTS_EXCEPTION(db.get_last_cc_hunt(moose, bears));
DB_TESTS_EXCEPTION(db.remove_last_cc_hunt());
db.add_cc_hunt(789, 111);
db.get_last_cc_hunt(moose, bears);
DB_TESTS_ASSERT(moose == 789);
DB_TESTS_ASSERT(bears == 111);
db.remove_last_cc_hunt();
DB_TESTS_EXCEPTION(db.get_last_cc_hunt(moose, bears));
return true;
}
bool db_tests_cc_trade_used(cryptonote::BlockchainDB &db)
{
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
db.set_cc_trade_used(8, 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
db.set_cc_trade_used(8, 5);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 5);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
db.set_cc_trade_used(8, 6);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 6);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
db.set_cc_trade_used(9, 2);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 6);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 2);
db.set_cc_trade_used(9, 1);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 6);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 1);
db.set_cc_trade_used(8, 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 1);
db.set_cc_trade_used(9, 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(0x1234567890ull) == 0);
db.set_cc_trade_used(0x1234567890ull, 3);
DB_TESTS_ASSERT(db.get_cc_trade_used(0x1234567890ull) == 3);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
db.set_cc_trade_used(9, 2);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 2);
db.set_cc_trade_used(8, 3);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 3);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 2);
db.set_cc_trade_used(8, 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 2);
db.set_cc_trade_used(9, 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(8) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(9) == 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(0x1234567890ull) == 3);
db.set_cc_trade_used(0x1234567890ull, 0);
DB_TESTS_ASSERT(db.get_cc_trade_used(0x1234567890ull) == 0);
return true;
}
bool db_tests_cc_used_nonces(cryptonote::BlockchainDB &db)
{
crypto::hash h = crypto::null_hash, hq;
h.data[0] = 4;
std::vector<uint32_t> a, aq;
a.push_back(2);
a.push_back(3);
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1));
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1, &aq, NULL));
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1, NULL, &hq));
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1, &aq, &hq));
db.add_cc_used_nonce(1, h);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1));
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, NULL, &hq));
DB_TESTS_ASSERT(hq == h);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, &aq, NULL));
DB_TESTS_ASSERT(aq.empty());
unsigned seen = 0;
db.for_all_cc_nonces_used([&seen, &h, &a](uint64_t nonce, const std::vector<uint32_t> &accounts, const crypto::hash &txid){
seen++;
DB_TESTS_ASSERT(accounts.empty());
DB_TESTS_ASSERT(txid == h);
return true;
});
DB_TESTS_ASSERT(seen == 1);
db.remove_cc_used_nonce(1);
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1));
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1, &aq, NULL));
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1, NULL, &hq));
DB_TESTS_ASSERT(!db.is_cc_nonce_used(1, &aq, &hq));
seen = 0;
db.for_all_cc_nonces_used([&seen](uint64_t nonce, const std::vector<uint32_t> &accounts, const crypto::hash &txid){ seen++; return true; });
DB_TESTS_ASSERT(seen == 0);
db.add_cc_used_nonce(1, a);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1));
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, NULL, &hq));
DB_TESTS_ASSERT(hq == crypto::null_hash);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, &aq, NULL));
DB_TESTS_ASSERT(aq == a);
seen = 0;
db.for_all_cc_nonces_used([&seen, &h, &a](uint64_t nonce, const std::vector<uint32_t> &accounts, const crypto::hash &txid){
seen++;
DB_TESTS_ASSERT(accounts == a);
DB_TESTS_ASSERT(txid == crypto::null_hash);
return true;
});
DB_TESTS_ASSERT(seen == 1);
db.add_cc_used_nonce(1, h);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1));
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, NULL, &hq));
DB_TESTS_ASSERT(hq == h);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, &aq, NULL));
DB_TESTS_ASSERT(aq == a);
seen = 0;
db.for_all_cc_nonces_used([&seen, &h, &a](uint64_t nonce, const std::vector<uint32_t> &accounts, const crypto::hash &txid){
seen++;
DB_TESTS_ASSERT(accounts == a);
DB_TESTS_ASSERT(txid == h);
return true;
});
DB_TESTS_ASSERT(seen == 1);
db.add_cc_used_nonce(1, crypto::null_hash);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1));
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, NULL, &hq));
DB_TESTS_ASSERT(hq == crypto::null_hash);
DB_TESTS_ASSERT(db.is_cc_nonce_used(1, &aq, NULL));
DB_TESTS_ASSERT(aq == a);
seen = 0;
db.for_all_cc_nonces_used([&seen, &h, &a](uint64_t nonce, const std::vector<uint32_t> &accounts, const crypto::hash &txid){
seen++;
DB_TESTS_ASSERT(accounts == a);
DB_TESTS_ASSERT(txid == crypto::null_hash);
return true;
});
DB_TESTS_ASSERT(seen == 1);
return true;
}
bool db_tests_cc_whispers(cryptonote::BlockchainDB &db)
{
cc::whisper_t whisper;
whisper.city = 1;
whisper.expiration = 1;
whisper.id = 0x42;
whisper.x = whisper.y = whisper.z = 1;
whisper.rx = whisper.ry = 2;
whisper.red = whisper.green = whisper.blue = 3;
whisper.message = "test 0x42";
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(0, [](const cc::whisper_t&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_EXCEPTION(db.remove_cc_whisper(whisper));
db.add_cc_whisper(whisper);
int seen = 0;
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(0, [](const cc::whisper_t&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(1, [&seen, &whisper](const cc::whisper_t &w) { DB_TESTS_ASSERT(w == whisper); ++seen; return true; }));
DB_TESTS_ASSERT(seen == 1);
++whisper.id;
DB_TESTS_EXCEPTION(db.remove_cc_whisper(whisper));
--whisper.id;
db.remove_cc_whisper(whisper);
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(0, [](const cc::whisper_t&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(1, [](const cc::whisper_t&) { DB_TESTS_ASSERT(false); return true; }));
db.add_cc_whisper(whisper);
++whisper.id;
whisper.city = 0;
db.add_cc_whisper(whisper);
++whisper.id;
++whisper.expiration;
whisper.city = 1;
db.add_cc_whisper(whisper);
// there's now 0x42 (exp 1) and 0x44 (exp 2) in 1, and 0x43 (exp 1) in 0
seen = 0;
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(0, [&seen](const cc::whisper_t &w) { DB_TESTS_ASSERT(w.id == 0x43); ++seen; return true; }));
DB_TESTS_ASSERT(seen == 1);
seen = 0;
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(1, [&seen](const cc::whisper_t &w) { DB_TESTS_ASSERT(w.id == 0x42 || w.id == 0x44); ++seen; return true; }));
DB_TESTS_ASSERT(seen == 2);
whisper.id -= 2;
whisper.city = 1;
--whisper.expiration;
cryptonote::block b;
db.add_block({b, cryptonote::block_to_blob(b)}, 100, 100, 100, 100, 2);
b.prev_id = cryptonote::get_block_hash(b);
b.invalidate_hashes();
db.add_block({b, cryptonote::block_to_blob(b)}, 100, 100, 100, 100, 2);
seen = 0;
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(0, [&seen](const cc::whisper_t &w) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_ASSERT(seen == 0);
seen = 0;
DB_TESTS_ASSERT(db.for_all_active_cc_whispers(1, [&seen](const cc::whisper_t &w) { DB_TESTS_ASSERT(w.id == 0x44); ++seen; return true; }));
DB_TESTS_ASSERT(seen == 1);
return true;
}
bool db_tests_cc_background_scripts(cryptonote::BlockchainDB &db)
{
typedef std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint32_t> ts_t;
std::vector<ts_t> ts;
uint64_t height;
DB_TESTS_EXCEPTION(db.remove_last_cc_background_scripts());
DB_TESTS_EXCEPTION(db.get_last_cc_background_scripts(height, ts));
ts.clear();
ts.push_back(std::make_tuple(1, 2, 3, 4, 5));
db.add_cc_background_scripts(GAME_UPDATE_FREQUENCY, ts);
ts.clear();
db.get_last_cc_background_scripts(height, ts);
DB_TESTS_ASSERT(height == GAME_UPDATE_FREQUENCY);
DB_TESTS_ASSERT(ts.size() == 1);
DB_TESTS_ASSERT(ts[0] == std::make_tuple(1, 2, 3, 4, 5));
ts.clear();
ts.push_back(std::make_tuple(11, 12, 13, 14, 15));
ts.push_back(std::make_tuple(21, 22, 23, 24, 25));
db.add_cc_background_scripts(GAME_UPDATE_FREQUENCY * 2, ts);
ts.clear();
db.get_last_cc_background_scripts(height, ts);
DB_TESTS_ASSERT(height == GAME_UPDATE_FREQUENCY * 2);
DB_TESTS_ASSERT(ts.size() == 2);
DB_TESTS_ASSERT(ts[0] == std::make_tuple(11, 12, 13, 14, 15));
DB_TESTS_ASSERT(ts[1] == std::make_tuple(21, 22, 23, 24, 25));
db.remove_last_cc_background_scripts();
ts.clear();
db.get_last_cc_background_scripts(height, ts);
DB_TESTS_ASSERT(height == GAME_UPDATE_FREQUENCY);
DB_TESTS_ASSERT(ts.size() == 1);
DB_TESTS_ASSERT(ts[0] == std::make_tuple(1, 2, 3, 4, 5));
db.remove_last_cc_background_scripts();
DB_TESTS_EXCEPTION(db.remove_last_cc_background_scripts());
DB_TESTS_EXCEPTION(db.get_last_cc_background_scripts(height, ts));
return true;
}
bool db_tests_cc_places(cryptonote::BlockchainDB &db)
{
cc::place_t place;
place.city = 1;
place.namer = 2;
place.x0 = 20;
place.y0 = 21;
place.x1 = 22;
place.y1 = 23;
place.name = "test 0x42";
place.id = 0;
DB_TESTS_ASSERT(db.for_all_cc_places(0, [](const cc::place_t&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_EXCEPTION(db.remove_last_cc_place(0));
DB_TESTS_ASSERT(db.add_cc_place(place) == 1);
int seen = 0;
DB_TESTS_ASSERT(db.for_all_cc_places(0, [](const cc::place_t&) { DB_TESTS_ASSERT(false); return true; }));
place.id = 1;
place.height = db.height();
DB_TESTS_ASSERT(db.for_all_cc_places(1, [&seen, &place](const cc::place_t &p) { DB_TESTS_ASSERT(p == place); ++seen; return true; }));
DB_TESTS_ASSERT(seen == 1);
DB_TESTS_EXCEPTION(db.remove_last_cc_place(0));
DB_TESTS_EXCEPTION(db.remove_last_cc_place(2));
DB_TESTS_EXCEPTION(db.remove_last_cc_place(0x42));
db.remove_last_cc_place(1);
DB_TESTS_ASSERT(db.for_all_cc_places(0, [](const cc::place_t&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_ASSERT(db.for_all_cc_places(1, [](const cc::place_t&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_ASSERT(db.add_cc_place(place) == 1);
++place.x0;
++place.y0;
++place.x1;
++place.y1;
place.name = "test 0x43";
DB_TESTS_ASSERT(db.add_cc_place(place) == 2);
// there's now 0x42 and 0x43, partially overlapping
DB_TESTS_ASSERT(db.for_all_cc_places(0, [](const cc::place_t&) { DB_TESTS_ASSERT(false); return true; }));
seen = 0;
DB_TESTS_ASSERT(db.for_all_cc_places(1, [&seen](const cc::place_t &p) {
const bool is_first = p.name == "test 0x42" && p.id == 1;
const bool is_second = p.name == "test 0x43" && p.id == 2;
DB_TESTS_ASSERT(is_first || is_second);
++seen;
return true;
}));
DB_TESTS_ASSERT(seen == 2);
return true;
}
bool db_tests_cc_user_textures(cryptonote::BlockchainDB &db)
{
uint8_t block;
uint32_t creator, width, height, hscale, vscale;
std::string description;
uint64_t creation_height;
bool recent;
cryptonote::block b;
db.add_block({b, cryptonote::block_to_blob(b)}, 100, 100, 100, 100, 2);
db.for_all_cc_textures([](uint32_t, uint64_t, uint8_t, uint32_t, uint32_t, uint32_t, const std::string&, uint32_t, uint32_t, uint64_t, bool){ DB_TESTS_ASSERT(false); return true; });
DB_TESTS_EXCEPTION(db.get_cc_texture_blob(1, block, creator, width, height, description, hscale, vscale, creation_height, recent));
DB_TESTS_EXCEPTION(db.delete_cc_texture(1));
uint32_t texture = db.allocate_new_cc_texture(0x42, 2, 1, 512, 512, "user texture", 6, 12);
DB_TESTS_ASSERT(texture == 1);
for (int i = 0; i < 2; ++i)
{
int seen = 0;
db.for_all_cc_textures([&seen](uint32_t texture, uint64_t nonce, uint8_t block, uint32_t creator, uint32_t width, uint32_t height, const std::string &description, uint32_t hscale, uint32_t vscale, uint64_t creation_height, bool recent){
DB_TESTS_ASSERT(texture == 1);
DB_TESTS_ASSERT(nonce == 0x42);
DB_TESTS_ASSERT(block == 2);
DB_TESTS_ASSERT(creator == 1);
DB_TESTS_ASSERT(width == 512);
DB_TESTS_ASSERT(height == 512);
DB_TESTS_ASSERT(description == "user texture");
DB_TESTS_ASSERT(hscale == 6);
DB_TESTS_ASSERT(vscale == 12);
DB_TESTS_ASSERT(creation_height == 1);
DB_TESTS_ASSERT(recent);
++seen;
return true;
}, i == 1);
DB_TESTS_ASSERT(seen == (i == 1 ? 1 : 0));
}
DB_TESTS_ASSERT(!db.does_cc_texture_exist(1, false));
DB_TESTS_ASSERT(db.does_cc_texture_exist(1, true));
DB_TESTS_ASSERT(!db.does_cc_texture_exist(0));
DB_TESTS_ASSERT(!db.does_cc_texture_exist(2));
DB_TESTS_EXCEPTION(db.delete_cc_texture(2));
db.delete_cc_texture(1);
DB_TESTS_ASSERT(!db.does_cc_texture_exist(1));
db.for_all_cc_textures([](uint32_t, uint64_t, uint8_t, uint32_t, uint32_t, uint32_t, const std::string&, uint32_t, uint32_t, uint64_t, bool){ DB_TESTS_ASSERT(false); return true; });
DB_TESTS_EXCEPTION(db.get_cc_texture_blob(1, block, creator, width, height, description, hscale, vscale, creation_height, recent));
DB_TESTS_EXCEPTION(db.delete_cc_texture(1));
return true;
}
bool db_tests_cc_merchant_ship_available_items(cryptonote::BlockchainDB &db)
{
std::vector<cc::merchant_ship_available_item_t> items;
db.get_cc_merchant_ship_available_items(items);
DB_TESTS_ASSERT(items.empty());
items.push_back({4, 10, 11, 12});
items.push_back({3, 20, 21, 22});
db.set_cc_merchant_ship_available_items(items);
items.clear();
db.get_cc_merchant_ship_available_items(items);
DB_TESTS_ASSERT(items.size() == 2);
// they get sorted by item
DB_TESTS_ASSERT(items[0] == cc::merchant_ship_available_item_t({3, 20, 21, 22}));
DB_TESTS_ASSERT(items[1] == cc::merchant_ship_available_item_t({4, 10, 11, 12}));
items.clear();
items.push_back({1, 2, 3, 4});
db.set_cc_merchant_ship_available_items(items);
items.clear();
db.get_cc_merchant_ship_available_items(items);
DB_TESTS_ASSERT(items.size() == 1);
DB_TESTS_ASSERT(items[0] == cc::merchant_ship_available_item_t({1, 2, 3, 4}));
items.clear();
db.set_cc_merchant_ship_available_items(items);
db.get_cc_merchant_ship_available_items(items);
DB_TESTS_ASSERT(items.empty());
return true;
}
bool db_tests_cc_merchant_ships(cryptonote::BlockchainDB &db)
{
uint32_t city, chan;
uint64_t height;
std::string ship_name, origin;
std::vector<uint64_t> nonces;
std::vector<std::tuple<uint32_t, uint32_t, uint64_t, std::vector<uint64_t>>> new_items;
std::vector<std::tuple<uint32_t, uint32_t, uint64_t, uint32_t, std::vector<uint64_t>>> items;
const uint32_t channel = cc::SPECIAL_EVENT_CHANNEL_TRADE1;
DB_TESTS_ASSERT(!db.get_cc_merchant_ship_data(0, channel, height, ship_name, origin, items));
DB_TESTS_EXCEPTION(db.remove_cc_merchant_ship(0, channel));
DB_TESTS_EXCEPTION(db.increase_cc_merchant_ship_sold(0, channel, 1, 1));
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(0, channel, 1, 1));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(0, city, chan));
for (uint64_t i = 0; i < 3; ++i)
nonces.push_back(1 + i);
new_items.push_back(std::make_tuple(ITEM_FIRST_USER + 42, 3000, 60000, nonces));
db.add_cc_merchant_ship(0, channel, 6, "Seagull", "Far away", new_items);
new_items.clear();
new_items.push_back(std::make_tuple(ITEM_FIRST_USER + 43, 1000, 90000, nonces));
DB_TESTS_EXCEPTION(db.add_cc_merchant_ship(0, channel, 1, "Kingfisher", "Further away", new_items));
DB_TESTS_ASSERT(!db.get_cc_merchant_ship_data(1, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(height == 6);
DB_TESTS_ASSERT(ship_name == "Seagull");
DB_TESTS_ASSERT(origin == "Far away");
DB_TESTS_ASSERT(items.size() == 1);
DB_TESTS_ASSERT(std::get<0>(items[0]) == ITEM_FIRST_USER + 42);
DB_TESTS_ASSERT(std::get<1>(items[0]) == 3000);
DB_TESTS_ASSERT(std::get<2>(items[0]) == 60000);
DB_TESTS_ASSERT(std::get<3>(items[0]) == 0);
DB_TESTS_ASSERT(std::get<4>(items[0]).size() == 3);
DB_TESTS_ASSERT(std::get<4>(items[0])[0] == 1);
DB_TESTS_ASSERT(std::get<4>(items[0])[1] == 2);
DB_TESTS_ASSERT(std::get<4>(items[0])[2] == 3);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(1, city, chan) && city == 0 && chan == channel);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(2, city, chan) && city == 0 && chan == channel);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(3, city, chan) && city == 0 && chan == channel);
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(4, city, chan));
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(0, channel, 1, 1));
DB_TESTS_EXCEPTION(db.increase_cc_merchant_ship_sold(0, channel, ITEM_FIRST_USER + 41, 500));
db.increase_cc_merchant_ship_sold(0, channel, ITEM_FIRST_USER + 42, 500);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(items.size() == 1);
DB_TESTS_ASSERT(std::get<3>(items[0]) == 500);
nonces.clear();
for (int i = 3; i < 5; ++i)
nonces.push_back(1 + i);
new_items.clear();
new_items.push_back(std::make_tuple(ITEM_FIRST_USER + 43, 1000, 90000, nonces));
db.add_cc_merchant_ship(1, channel, 30, "Kingfisher", "Further away", new_items);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(height == 30);
DB_TESTS_ASSERT(ship_name == "Kingfisher");
DB_TESTS_ASSERT(origin == "Further away");
DB_TESTS_ASSERT(items.size() == 1);
DB_TESTS_ASSERT(std::get<0>(items[0]) == ITEM_FIRST_USER + 43);
DB_TESTS_ASSERT(std::get<1>(items[0]) == 1000);
DB_TESTS_ASSERT(std::get<2>(items[0]) == 90000);
DB_TESTS_ASSERT(std::get<3>(items[0]) == 0);
DB_TESTS_ASSERT(std::get<4>(items[0]).size() == 2);
DB_TESTS_ASSERT(std::get<4>(items[0])[0] == 4);
DB_TESTS_ASSERT(std::get<4>(items[0])[1] == 5);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(4, city, chan) && city == 1 && chan == channel);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(5, city, chan) && city == 1 && chan == channel);
db.increase_cc_merchant_ship_sold(1, channel, ITEM_FIRST_USER + 43, 200);
db.increase_cc_merchant_ship_sold(0, channel, ITEM_FIRST_USER + 42, 500);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(std::get<3>(items[0]) == 1000);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(std::get<3>(items[0]) == 200);
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(1, channel, ITEM_FIRST_USER + 43, 201));
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(0, channel, ITEM_FIRST_USER + 43, 1001));
db.decrease_cc_merchant_ship_sold(1, channel, ITEM_FIRST_USER + 43, 200);
db.decrease_cc_merchant_ship_sold(0, channel, ITEM_FIRST_USER + 42, 1000);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(std::get<3>(items[0]) == 0);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(std::get<3>(items[0]) == 0);
db.remove_cc_merchant_ship(0, channel);
DB_TESTS_ASSERT(!db.get_cc_merchant_ship_data(0, channel, height, ship_name, origin, items));
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, channel, height, ship_name, origin, items));
DB_TESTS_EXCEPTION(db.remove_cc_merchant_ship(0, channel));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(1, city, chan));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(2, city, chan));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(3, city, chan));
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(4, city, chan) && city == 1 && chan == channel);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(5, city, chan) && city == 1 && chan == channel);
db.remove_cc_merchant_ship(1, channel);
return true;
}
bool db_tests_cc_epochs(cryptonote::BlockchainDB &db)
{
std::vector<cc::cc_epoch_t> epochs;
epochs = db.get_cc_epochs();
DB_TESTS_ASSERT(epochs.empty());
DB_TESTS_EXCEPTION(db.remove_cc_last_epoch());
DB_TESTS_EXCEPTION(db.get_cc_epoch(0));
const cc::cc_epoch_t e0Landfall_open_ended{0, "Landfall", 0, (int64_t)-1};
const cc::cc_epoch_t e0Landfall_over{0, "Landfall", 0, 2};
const cc::cc_epoch_t e1Exploration{1, "Exploration", 2, (int64_t)-1};
db.start_cc_epoch("Landfall"); // at 0
DB_TESTS_ASSERT(db.get_cc_epoch(0) == e0Landfall_open_ended);
DB_TESTS_ASSERT(db.get_cc_epoch(1) == e0Landfall_open_ended);
epochs = db.get_cc_epochs();
DB_TESTS_ASSERT(epochs.size() == 1);
DB_TESTS_ASSERT(epochs[0] == e0Landfall_open_ended);
cryptonote::block b;
db.add_block({b, cryptonote::block_to_blob(b)}, 100, 100, 100, 100, 2);
b.prev_id = cryptonote::get_block_hash(b);
b.invalidate_hashes();
db.add_block({b, cryptonote::block_to_blob(b)}, 100, 100, 100, 100, 2);
db.start_cc_epoch("Exploration"); // at 2
DB_TESTS_ASSERT(db.get_cc_epoch(0) == e0Landfall_over);
DB_TESTS_ASSERT(db.get_cc_epoch(1) == e0Landfall_over);
DB_TESTS_ASSERT(db.get_cc_epoch(2) == e1Exploration);
epochs = db.get_cc_epochs();
DB_TESTS_ASSERT(epochs.size() == 2);
DB_TESTS_ASSERT(epochs[0] == e0Landfall_over);
DB_TESTS_ASSERT(epochs[1] == e1Exploration);
db.remove_cc_last_epoch();
epochs = db.get_cc_epochs();
DB_TESTS_ASSERT(epochs.size() == 1);
DB_TESTS_ASSERT(epochs[0] == e0Landfall_open_ended);
DB_TESTS_ASSERT(db.get_cc_epoch(0) == e0Landfall_open_ended);
DB_TESTS_ASSERT(db.get_cc_epoch(1) == e0Landfall_open_ended);
db.remove_cc_last_epoch();
epochs = db.get_cc_epochs();
DB_TESTS_ASSERT(epochs.empty());
DB_TESTS_EXCEPTION(db.get_cc_epoch(0));
DB_TESTS_EXCEPTION(db.remove_cc_last_epoch());
return true;
}
bool db_tests_cc_coru_requests(cryptonote::BlockchainDB &db)
{
std::vector<cc::coru_request_t> requests;
cc::coru_request_t request;
crypto::hash hash1, hash2;
hash1 = crypto::null_hash;
hash1.data[4] = 1;
hash2 = crypto::null_hash;
hash2.data[4] = 2;
db.get_cc_coru_requests(requests);
DB_TESTS_ASSERT(requests.empty());
request.nonce = 0x80;
request.account = 5;
request.player = 7;
request.until_height = 77;
request.min_wager = 35;
request.max_wager = 53;
request.deck_commitment = hash2;
db.add_cc_coru_request(hash1, request);
db.get_cc_coru_requests(requests);
DB_TESTS_ASSERT(requests.size() == 1);
DB_TESTS_ASSERT(requests[0].nonce == 0x80);
DB_TESTS_ASSERT(requests[0].account == 5);
DB_TESTS_ASSERT(requests[0].player == 7);
DB_TESTS_ASSERT(requests[0].until_height == 77);
DB_TESTS_ASSERT(requests[0].min_wager == 35);
DB_TESTS_ASSERT(requests[0].max_wager == 53);
DB_TESTS_ASSERT(requests[0].deck_commitment == hash2);
db.remove_cc_coru_request(0x100); // nop
db.get_cc_coru_requests(requests);
DB_TESTS_ASSERT(requests.size() == 1);
db.remove_cc_coru_request(0x80);
db.get_cc_coru_requests(requests);
DB_TESTS_ASSERT(requests.empty());
return true;
}
bool db_tests_cc_coru_games(cryptonote::BlockchainDB &db)
{
cc::coru_game_state_t coru;
uint32_t found = 0;
db.for_all_cc_coru_games([&found](const cc::coru_game_state_t &c) { ++found; return true; }, false);
DB_TESTS_ASSERT(found == 0);
db.for_all_cc_coru_games([&found](const cc::coru_game_state_t &c) { ++found; return true; }, true);
DB_TESTS_ASSERT(found == 0);
DB_TESTS_EXCEPTION(db.get_last_cc_coru_game_id());
DB_TESTS_EXCEPTION(db.delete_last_cc_coru_game());
DB_TESTS_ASSERT(!db.get_cc_coru_game(0, coru));
DB_TESTS_ASSERT(!db.get_cc_coru_game(1, coru));
cc::coru_player_t players[2];
players[0].id = 35;
players[0].commitment = crypto::null_hash;
players[0].commitment.data[21] = 0x42;
players[0].deck.coins.push_back(4);
players[0].deck.coins.push_back(6);
players[0].deck.runes.push_back(4098);
players[1].id = 111111;
players[1].commitment = crypto::null_hash;
players[1].commitment.data[5] = 0x21;
players[0].deck.coins.push_back(400);
players[0].deck.coins.push_back(500);
players[0].deck.runes.clear();
uint32_t id1 = db.start_cc_coru_game(players, "foo", 12, false, 4, 30);
DB_TESTS_ASSERT(id1 == 1);
DB_TESTS_ASSERT(db.get_last_cc_coru_game_id() == 1);
const uint64_t height = db.height();
cc::coru_game_state_t cr;
for (int i = 0; i < 2; ++i)
{
found = 0;
db.for_all_cc_coru_games([&players, height, &found, &cr](const cc::coru_game_state_t &c) {
DB_TESTS_ASSERT(c.id == 1);
DB_TESTS_ASSERT(c.name == "foo");
DB_TESTS_ASSERT(c.winner == 0);
DB_TESTS_ASSERT(c.players[0] == players[0]);
DB_TESTS_ASSERT(c.players[1] == players[1]);
DB_TESTS_ASSERT(c.rounds.size() == 1);
DB_TESTS_ASSERT(c.rounds[0].turn == 0);
DB_TESTS_ASSERT(c.rounds[0].start_height == height);
DB_TESTS_ASSERT(c.rounds[0].first_player_index == 0);
DB_TESTS_ASSERT(c.rounds[0].outcome == CORU_ROUND_ONGOING);
DB_TESTS_ASSERT(c.game_start_height == height);
DB_TESTS_ASSERT(c.game_turn == 0);
DB_TESTS_ASSERT(c.turn_start_height == height);
DB_TESTS_ASSERT(c.rounds_to_win == 4);
DB_TESTS_ASSERT(c.wager == 12);
DB_TESTS_ASSERT(!c.jeopardy);
DB_TESTS_ASSERT(c.max_turn_time == 30);
++found;
cr = c;
return true;
}, i == 0);
DB_TESTS_ASSERT(found == 1);
}
DB_TESTS_ASSERT(!db.get_cc_coru_game(0, coru));
DB_TESTS_ASSERT(db.get_cc_coru_game(1, coru));
DB_TESTS_ASSERT(coru == cr);
DB_TESTS_ASSERT(!db.get_cc_coru_game(2, coru));
db.delete_last_cc_coru_game();
DB_TESTS_EXCEPTION(db.delete_last_cc_coru_game());
found = 0;
db.for_all_cc_coru_games([&found](const cc::coru_game_state_t &c) { ++found; return true; }, false);
DB_TESTS_ASSERT(found == 0);
db.for_all_cc_coru_games([&found](const cc::coru_game_state_t &c) { ++found; return true; }, true);
DB_TESTS_ASSERT(found == 0);
DB_TESTS_ASSERT(!db.get_cc_coru_game(0, coru));
DB_TESTS_ASSERT(!db.get_cc_coru_game(1, coru));
DB_TESTS_EXCEPTION(db.get_last_cc_coru_game_id());
return true;
}
bool db_tests_cc_coru_tournaments(cryptonote::BlockchainDB &db)
{
cc::coru_tournament_state_t coru;
uint32_t found = 0;
db.for_all_cc_coru_tournaments([&found](const cc::coru_tournament_state_t &c) { ++found; return true; }, false);
DB_TESTS_ASSERT(found == 0);
db.for_all_cc_coru_tournaments([&found](const cc::coru_tournament_state_t &c) { ++found; return true; }, true);
DB_TESTS_ASSERT(found == 0);
DB_TESTS_EXCEPTION(db.get_last_cc_coru_tournament_id());
DB_TESTS_EXCEPTION(db.delete_last_cc_coru_tournament());
DB_TESTS_ASSERT(!db.get_cc_coru_tournament(0, coru));
DB_TESTS_ASSERT(!db.get_cc_coru_tournament(1, coru));
std::vector<std::pair<uint64_t, std::vector<std::pair<uint32_t, uint32_t>>>> prizes(2);
prizes[0].first = 255;
prizes[0].second.push_back(std::make_pair(7, 8));
prizes[1].first = 2555;
prizes[1].second.push_back(std::make_pair(2, 4));
prizes[1].second.push_back(std::make_pair(6, 8));
uint32_t id1 = db.create_cc_coru_tournament("bar", 60, prizes, 888, 130);
DB_TESTS_ASSERT(id1 == 1);
DB_TESTS_ASSERT(db.get_last_cc_coru_tournament_id() == 1);
const uint64_t height = db.height();
cc::coru_tournament_state_t cr;
for (int i = 0; i < 2; ++i)
{
found = 0;
db.for_all_cc_coru_tournaments([&prizes, height, &found, &cr](const cc::coru_tournament_state_t &c) {
DB_TESTS_ASSERT(c.id == 1);
DB_TESTS_ASSERT(c.creator == 60);
DB_TESTS_ASSERT(c.name == "bar");
DB_TESTS_ASSERT(c.end_height == 0);
DB_TESTS_ASSERT(c.entrants.empty());
DB_TESTS_ASSERT(c.prizes == prizes);
DB_TESTS_ASSERT(c.start_height == 888);
DB_TESTS_ASSERT(c.registration_fee == 130);
DB_TESTS_ASSERT(c.n_rounds == 0);
DB_TESTS_ASSERT(c.rounds.empty());
DB_TESTS_ASSERT(c.byes.empty());
DB_TESTS_ASSERT(c.wins.empty());
++found;
cr = c;
return true;
}, i == 0);
DB_TESTS_ASSERT(found == 1);
}
DB_TESTS_ASSERT(!db.get_cc_coru_tournament(0, coru));
DB_TESTS_ASSERT(db.get_cc_coru_tournament(1, coru));
DB_TESTS_ASSERT(coru == cr);
DB_TESTS_ASSERT(!db.get_cc_coru_tournament(2, coru));
db.delete_last_cc_coru_tournament();
DB_TESTS_EXCEPTION(db.delete_last_cc_coru_tournament());
found = 0;
db.for_all_cc_coru_tournaments([&found](const cc::coru_tournament_state_t &c) { ++found; return true; }, false);
DB_TESTS_ASSERT(found == 0);
db.for_all_cc_coru_tournaments([&found](const cc::coru_tournament_state_t &c) { ++found; return true; }, true);
DB_TESTS_ASSERT(found == 0);
DB_TESTS_ASSERT(!db.get_cc_coru_tournament(0, coru));
DB_TESTS_ASSERT(!db.get_cc_coru_tournament(1, coru));
DB_TESTS_EXCEPTION(db.get_last_cc_coru_tournament_id());
return true;
}
bool db_tests_cc_trustee_balances(cryptonote::BlockchainDB &db)
{
std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> balances;
crypto::public_key key1 = crypto::null_pkey; key1.data[0] = 1;
crypto::public_key key2 = crypto::null_pkey; key2.data[0] = 2;
crypto::public_key key3 = crypto::null_pkey; key3.data[0] = 3;
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.empty());
db.change_cc_trustee_balance(key1, 0, 0);
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.empty());
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key2) == std::make_pair(0ul, 0ul));
DB_TESTS_EXCEPTION(db.change_cc_trustee_balance(key1, -1, 0));
DB_TESTS_EXCEPTION(db.change_cc_trustee_balance(key1, 0, -1));
db.change_cc_trustee_balance(key1, 0, 18);
DB_TESTS_EXCEPTION(db.change_cc_trustee_balance(key1, 0, -19));
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key1) == std::make_pair(0ul, 18ul));
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.size() == 1);
DB_TESTS_ASSERT(balances.begin()->first == key1);
DB_TESTS_ASSERT(balances.begin()->second.first == 0);
DB_TESTS_ASSERT(balances.begin()->second.second == 18);
db.change_cc_trustee_balance(key2, 2, 0);
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.size() == 2);
DB_TESTS_ASSERT(balances.find(key1) != balances.end());
DB_TESTS_ASSERT(balances.find(key2) != balances.end());
DB_TESTS_ASSERT(balances.find(key3) == balances.end());
DB_TESTS_ASSERT(balances.find(key1)->second.first == 0);
DB_TESTS_ASSERT(balances.find(key1)->second.second == 18);
DB_TESTS_ASSERT(balances.find(key2)->second.first == 2);
DB_TESTS_ASSERT(balances.find(key2)->second.second == 0);
db.change_cc_trustee_balance(key2, 40, 6);
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.size() == 2);
DB_TESTS_ASSERT(balances.find(key1) != balances.end());
DB_TESTS_ASSERT(balances.find(key2) != balances.end());
DB_TESTS_ASSERT(balances.find(key3) == balances.end());
DB_TESTS_ASSERT(balances.find(key1)->second == std::make_pair(0ul, 18ul));
DB_TESTS_ASSERT(balances.find(key2)->second == std::make_pair(42ul, 6ul));
db.change_cc_trustee_balance(key1, 0, -18);
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.size() == 1);
DB_TESTS_ASSERT(balances.find(key2) != balances.end());
DB_TESTS_ASSERT(balances.find(key3) == balances.end());
DB_TESTS_ASSERT(balances.find(key2)->second == std::make_pair(42ul, 6ul));
db.change_cc_trustee_balance(key1, 8, 5);
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.size() == 2);
DB_TESTS_ASSERT(balances.find(key1) != balances.end());
DB_TESTS_ASSERT(balances.find(key2) != balances.end());
DB_TESTS_ASSERT(balances.find(key3) == balances.end());
DB_TESTS_ASSERT(balances.find(key1)->second == std::make_pair(8ul, 5ul));
DB_TESTS_ASSERT(balances.find(key2)->second == std::make_pair(42ul, 6ul));
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key1) == std::make_pair(8ul, 5ul));
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key2) == std::make_pair(42ul, 6ul));
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key3) == std::make_pair(0ul, 0ul));
db.change_cc_trustee_balance(key1, 2, -2);
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key1) == std::make_pair(10ul, 3ul));
db.change_cc_trustee_balance(key1, -5, -2);
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key1) == std::make_pair(5ul, 1ul));
DB_TESTS_EXCEPTION(db.change_cc_trustee_balance(key1, -6, 10));
DB_TESTS_EXCEPTION(db.change_cc_trustee_balance(key1, 10, -2));
DB_TESTS_EXCEPTION(db.change_cc_trustee_balance(key1, -6, -2));
db.change_cc_trustee_balance(key1, -5, -1);
db.change_cc_trustee_balance(key2, -42, -6);
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key1) == std::make_pair(0ul, 0ul));
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key2) == std::make_pair(0ul, 0ul));
DB_TESTS_ASSERT(db.get_cc_trustee_balance(key3) == std::make_pair(0ul, 0ul));
db.get_cc_trustee_balances(balances);
DB_TESTS_ASSERT(balances.empty());
return true;
}
bool db_tests_cc_flag_ownership_changes(cryptonote::BlockchainDB &db)
{
DB_TESTS_ASSERT(cc::add_init_state(db));
DB_TESTS_EXCEPTION(db.revert_cc_flag_ownership_changes(0, 1));
DB_TESTS_EXCEPTION(db.revert_cc_flag_ownership_changes(1, 1));
DB_TESTS_EXCEPTION(db.revert_cc_flag_ownership_changes(2, 1));
cryptonote::cc_flag_data_t fd;
DB_TESTS_ASSERT(db.get_cc_flag_data(1, fd));
fd.recent_ownership_changes = 0;
db.set_cc_flag_data(1, fd);
DB_TESTS_EXCEPTION(db.record_cc_flag_ownership_changes(1, 1));
fd.recent_ownership_changes = 7498;
db.set_cc_flag_data(1, fd);
db.record_cc_flag_ownership_changes(1, 1);
DB_TESTS_EXCEPTION(db.record_cc_flag_ownership_changes(1, 1));
DB_TESTS_ASSERT(db.get_cc_flag_data(1, fd));
DB_TESTS_ASSERT(fd.recent_ownership_changes == 0);
DB_TESTS_EXCEPTION(db.record_cc_flag_ownership_changes(1, 1));
DB_TESTS_EXCEPTION(db.revert_cc_flag_ownership_changes(1, 2));
DB_TESTS_EXCEPTION(db.revert_cc_flag_ownership_changes(2, 1));
db.revert_cc_flag_ownership_changes(1, 1);
DB_TESTS_EXCEPTION(db.revert_cc_flag_ownership_changes(1, 1));
DB_TESTS_ASSERT(db.get_cc_flag_data(1, fd));
DB_TESTS_ASSERT(fd.recent_ownership_changes == 7498);
return true;
}
bool db_tests_cc_vistas(cryptonote::BlockchainDB &db)
{
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 0, [](uint32_t, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { DB_TESTS_ASSERT(false); return true; }));
DB_TESTS_EXCEPTION(db.revert_last_cc_vista());
DB_TESTS_ASSERT(db.add_cc_vista(0, 1, "vista1", "note1", "pic1") == 1);
DB_TESTS_ASSERT(db.add_cc_vista(0, 2, "vista2", "note2", "pic2") == 2);
int seen = 0;
DB_TESTS_ASSERT(db.for_all_cc_vistas(1, 0, [](uint32_t, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { DB_TESTS_ASSERT(false); return true; }));
std::map<uint32_t, uint32_t> seen_id;
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 0, [&seen_id](uint32_t id, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { ++seen_id[id]; return true; }));
DB_TESTS_ASSERT(seen_id.size() == 2);
DB_TESTS_ASSERT(seen_id[1] == 1);
DB_TESTS_ASSERT(seen_id[2] == 1);
seen_id.clear();
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 1, [&seen_id](uint32_t id, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { ++seen_id[id]; return true; }));
DB_TESTS_ASSERT(seen_id.size() == 1);
DB_TESTS_ASSERT(seen_id[1] == 1);
seen_id.clear();
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 2, [&seen_id](uint32_t id, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { ++seen_id[id]; return true; }));
DB_TESTS_ASSERT(seen_id.size() == 1);
DB_TESTS_ASSERT(seen_id[2] == 1);
seen = 0;
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 3, [&seen](uint32_t, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { ++seen; return true; }));
DB_TESTS_ASSERT(seen == 0);
db.revert_last_cc_vista();
seen = 0;
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 1, [&seen](uint32_t id, uint32_t city, uint32_t player, const std::string &vista, const std::string &note, const std::string &picture) {
++seen;
DB_TESTS_ASSERT(city == 0);
DB_TESTS_ASSERT(player == 1);
DB_TESTS_ASSERT(vista == "vista1");
DB_TESTS_ASSERT(note == "note1");
DB_TESTS_ASSERT(picture == "pic1");
return true;
}));
DB_TESTS_ASSERT(seen == 1);
seen_id.clear();
DB_TESTS_ASSERT(db.for_all_cc_vistas(0, 2, [&seen_id](uint32_t id, uint32_t, uint32_t, const std::string&, const std::string&, const std::string&) { ++seen_id[id]; return true; }));
DB_TESTS_ASSERT(seen_id.empty());
db.revert_last_cc_vista();
DB_TESTS_EXCEPTION(db.revert_last_cc_vista());
return true;
}