townforge/tests/db_tests/db_tests_cc.cpp

991 lines
36 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_script.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", "blob", false, 42, true);
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.owner == 42);
DB_TESTS_ASSERT(s.is_public == true);
DB_TESTS_ASSERT(s.enabled == true);
++n_scripts;
return true;
}));
DB_TESTS_ASSERT(n_scripts == 1);
const uint32_t id2 = db.allocate_new_cc_script("name2", "icon2", "desc2", "blob2", false, 43, false);
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.owner == (s.id == id ? 42 : 43));
DB_TESTS_ASSERT(s.is_public == (s.id == id));
DB_TESTS_ASSERT(s.enabled);
++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, "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.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, 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, 200, 200));
db.add_cc_auction_bid(1, 3, 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, 200, 200));
DB_TESTS_ASSERT(ad.bids[1] == std::make_tuple(3, 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_cc_auction_bid(1, 3, 400, 300);
db.remove_cc_auction_bid(1, 2, 200, 200);
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(720, ts);
ts.clear();
db.get_last_cc_background_scripts(height, ts);
DB_TESTS_ASSERT(height == 720);
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(1440, ts);
ts.clear();
db.get_last_cc_background_scripts(height, ts);
DB_TESTS_ASSERT(height == 1440);
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 == 720);
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.id = 0x42;
place.x0 = 20;
place.y0 = 21;
place.x1 = 22;
place.y1 = 23;
place.name = "test 0x42";
place.priority = 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_cc_place(place));
db.add_cc_place(place);
int seen = 0;
DB_TESTS_ASSERT(db.for_all_cc_places(0, [](const cc::place_t&) { DB_TESTS_ASSERT(false); return true; }));
place.priority = 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);
++place.id;
DB_TESTS_EXCEPTION(db.remove_cc_place(place));
--place.id;
db.remove_cc_place(place);
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.add_cc_place(place);
++place.id;
++place.x0;
++place.y0;
++place.x1;
++place.y1;
place.name = "test 0x43";
db.add_cc_place(place);
// 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.id == 0x42 && p.name == "test 0x42" && p.priority == 1;
const bool is_second = p.id == 0x43 && p.name == "test 0x43" && p.priority == 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;
db.for_all_cc_textures([](uint32_t, uint64_t, uint8_t, uint32_t, uint32_t, uint32_t, const std::string&, uint32_t, uint32_t){ DB_TESTS_ASSERT(false); return true; });
DB_TESTS_EXCEPTION(db.get_cc_texture_blob(1, block, creator, width, height, description, hscale, vscale));
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);
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){
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);
++seen;
return true;
});
DB_TESTS_ASSERT(seen == 1);
DB_TESTS_ASSERT(db.does_cc_texture_exist(1));
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){ DB_TESTS_ASSERT(false); return true; });
DB_TESTS_EXCEPTION(db.get_cc_texture_blob(1, block, creator, width, height, description, hscale, vscale));
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, item, amount, sold;
uint64_t height, price;
std::string ship_name, origin;
std::vector<uint64_t> nonces;
DB_TESTS_ASSERT(!db.get_cc_merchant_ship_data(0, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_EXCEPTION(db.remove_cc_merchant_ship(0));
DB_TESTS_EXCEPTION(db.increase_cc_merchant_ship_sold(0, 1));
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(0, 1));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(0, city));
for (uint64_t i = 0; i < 3; ++i)
nonces.push_back(1 + i);
db.add_cc_merchant_ship(0, 6, "Seagull", "Far away", ITEM_FIRST_USER + 42, 3000, 60000, nonces);
DB_TESTS_EXCEPTION(db.add_cc_merchant_ship(0, 1, "Kingfisher", "Further away", ITEM_FIRST_USER + 43, 1000, 90000, nonces));
DB_TESTS_ASSERT(!db.get_cc_merchant_ship_data(1, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(height == 6);
DB_TESTS_ASSERT(ship_name == "Seagull");
DB_TESTS_ASSERT(origin == "Far away");
DB_TESTS_ASSERT(item == ITEM_FIRST_USER + 42);
DB_TESTS_ASSERT(amount == 3000);
DB_TESTS_ASSERT(price == 60000);
DB_TESTS_ASSERT(sold == 0);
DB_TESTS_ASSERT(nonces.size() == 3);
DB_TESTS_ASSERT(nonces[0] == 1);
DB_TESTS_ASSERT(nonces[1] == 2);
DB_TESTS_ASSERT(nonces[2] == 3);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(1, city) && city == 0);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(2, city) && city == 0);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(3, city) && city == 0);
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(4, city));
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(0, 1));
db.increase_cc_merchant_ship_sold(0, 500);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(sold == 500);
nonces.clear();
for (int i = 3; i < 5; ++i)
nonces.push_back(1 + i);
db.add_cc_merchant_ship(1, 30, "Kingfisher", "Further away", ITEM_FIRST_USER + 43, 1000, 90000, nonces);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(height == 30);
DB_TESTS_ASSERT(ship_name == "Kingfisher");
DB_TESTS_ASSERT(origin == "Further away");
DB_TESTS_ASSERT(item == ITEM_FIRST_USER + 43);
DB_TESTS_ASSERT(amount == 1000);
DB_TESTS_ASSERT(price == 90000);
DB_TESTS_ASSERT(sold == 0);
DB_TESTS_ASSERT(nonces.size() == 2);
DB_TESTS_ASSERT(nonces[0] == 4);
DB_TESTS_ASSERT(nonces[1] == 5);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(4, city) && city == 1);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(5, city) && city == 1);
db.increase_cc_merchant_ship_sold(1, 200);
db.increase_cc_merchant_ship_sold(0, 500);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(sold == 1000);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(sold == 200);
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(1, 201));
DB_TESTS_EXCEPTION(db.decrease_cc_merchant_ship_sold(0, 1001));
db.decrease_cc_merchant_ship_sold(1, 200);
db.decrease_cc_merchant_ship_sold(0, 1000);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(0, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(sold == 0);
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(sold == 0);
db.remove_cc_merchant_ship(0);
DB_TESTS_ASSERT(!db.get_cc_merchant_ship_data(0, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_ASSERT(db.get_cc_merchant_ship_data(1, height, ship_name, origin, item, amount, price, sold, nonces));
DB_TESTS_EXCEPTION(db.remove_cc_merchant_ship(0));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(1, city));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(2, city));
DB_TESTS_ASSERT(!db.is_cc_merchant_ship_transaction(3, city));
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(4, city) && city == 1);
DB_TESTS_ASSERT(db.is_cc_merchant_ship_transaction(5, city) && city == 1);
db.remove_cc_merchant_ship(1);
return true;
}