game accounts can now be auctioned

can only be withdrawn from at the moment
This commit is contained in:
Crypto City 2023-05-25 19:54:18 +00:00
parent d8c357153a
commit 8ea9160fca
68 changed files with 2302 additions and 150 deletions

View File

@ -0,0 +1,33 @@
WindowInfo
title Auction account
centered-relative-size: 0.7 0.8
modal: 1
TBLayout: axis: y, distribution-position: "left top", distribution: "available"
TBEditField: multiline: 1, readonly: 1, gravity: "left right", adapt-to-content: 1, skin: "TBEditField.select-items-message", is-focusable: 0
text: "While your account is being auctioned, you will not be able to control it anymore."
TBLayout: axis: x
TBTextField: text: "Duration (days)"
TBInlineSelect: id: "duration", min: 2, max: 14
TBButton: text: "Help", id: "help"
TBLayout: axis: x
TBTextField: text: "Reserve price"
TBEditField: id: "reserve-price", placeholder: "0"
TBToggleContainer: id: "reserve-price-error-container", toggle: "expanded", gravity: "left right"
TBLayout: axis: x, distribution: "gravity", distribution-position: "left"
TBImageWidget: filename: "images/warning.png"
lp:
width: 24
height: 24
TBTextField: id: "reserve-price-error", gravity: "left right", text-align: "left", skin: "text-error"
TBEditField: id: "title", placeholder: "Title (optional)", gravity: "left right"
TBEditField: id: "description", multiline: 1, placeholder: "Description (optional)", gravity: "all"
TBLayout: axis: x
TBButton: text: "OK", id: "ok"
TBButton: text: "Cancel", id: "cancel"

View File

@ -17,6 +17,17 @@ TBLayout: axis: y, distribution-position: "left top", distribution: "available"
TBInlineSelect: id: "duration", min: 2, max: 14
TBButton: text: "Help", id: "help"
TBLayout: axis: x
TBTextField: text: "Reserve price"
TBEditField: id: "reserve-price", placeholder: "0"
TBToggleContainer: id: "reserve-price-error-container", toggle: "expanded", gravity: "left right"
TBLayout: axis: x, distribution: "gravity", distribution-position: "left"
TBImageWidget: filename: "images/warning.png"
lp:
width: 24
height: 24
TBTextField: id: "reserve-price-error", gravity: "left right", text-align: "left", skin: "text-error"
TBEditField: id: "title", placeholder: "Title (optional)", gravity: "left right"
TBEditField: id: "description", multiline: 1, placeholder: "Description (optional)", gravity: "all"

View File

@ -9,8 +9,14 @@ TBLayout: axis: y, position: "left", ignore-input: 1, size: "available"
TBTextField: id: "name", gravity: "left", text-align: "left"
TBTextField: id: "deadline", gravity: "right", text-align: "right"
TBToggleContainer: id: "details-container", toggle: "expanded, value: 0
TBLayout: axis: x
TBSeparator
lp:
width: 48
TBEditField: id: "details", text: "a\nb\nc\nd\ne\nf\ng\nh\n", multiline: 1, readonly: 1, adapt-to-content: 1, is-focusable: 0, skin: "TBEditField.item-description", gravity: "left right"
TBLayout: axis: y
TBToggleContainer: id: "reserve-price-container", toggle: "expanded"
TBLayout: axis: x
TBTextField: text: "Reserve price:"
TBTextField: id: "reserve-price"
TBTextField: text: "gold"
TBLayout: axis: x
TBSeparator
lp:
width: 48
TBEditField: id: "details", text: "a\nb\nc\nd\ne\nf\ng\nh\n", multiline: 1, readonly: 1, adapt-to-content: 1, is-focusable: 0, skin: "TBEditField.item-description", gravity: "left right"

View File

@ -48,6 +48,10 @@ TBLayout: axis: y, distribution-position: "center top", distribution: "available
TBTextField: text: "", id: "player-wallet-balance"
TBButton: skin: "TBButton.column", text: "Deposit" id: "player-deposit"
TBButton: skin: "TBButton.column", text: "Withdraw" id: "player-withdraw"
TBToggleContainer: id: "balance-held-in-trust-container", toggle: "expanded"
TBTextField: text: "Balance held in trust:"
TBTextField: text: "", id: "balance-held-in-trust"
TBButton: id: "withdraw-trustee", text: "Withdraw"
TBButton: skin: "TBButton.column", text: "Load wallet" id: "player-load-wallet"
TBSection: value: 0, text: "Social", id: "social-section"

View File

@ -13,6 +13,17 @@ TBLayout: axis: y, distribution-position: "left top", distribution: "gravity"
TBTextField: text: "Duration (days)"
TBInlineSelect: id: "duration", min: 2, max: 14
TBLayout: axis: x
TBTextField: text: "Reserve price"
TBEditField: id: "reserve-price", placeholder: "0"
TBToggleContainer: id: "reserve-price-error-container", toggle: "expanded", gravity: "left right"
TBLayout: axis: x, distribution: "gravity", distribution-position: "left"
TBImageWidget: filename: "images/warning.png"
lp:
width: 24
height: 24
TBTextField: id: "reserve-price-error", gravity: "left right", text-align: "left", skin: "text-error"
TBEditField: id: "title", placeholder: "Title (optional)", gravity: "left right"
TBToggleContainer: id: "title-error-container", toggle: "expanded", gravity: "left right"
TBLayout: axis: x, distribution: "gravity", distribution-position: "left"

View File

@ -24,10 +24,12 @@ TBTabContainer
TBLayout: axis: y, distribution: "gravity", gravity: "top bottom", distribution-position: "left", size: "available"
TBLayout: axis: x, distribution-position: "top", gravity: "top"
TBLayout: axis: y, distribution-position: "top left"
TBLayout: axis: x, distribution-position: "left top"
TBLayout: axis: x, distribution-position: "left top", distribution: "gravity", size_ "available"
TBTextField: text: "Name:"
TBTextField: id: "name"
TBButton: id: "select-account", text: "Select other"
TBTextField: gravity: "left right"
TBButton: id: "auction-account", text: "Auction account", gravity: "right"
TBLayout: axis: x, distribution-position: "left top"
TBTextField: text: "Level:"
TBTextField: id: "level"

View File

@ -2081,6 +2081,7 @@ public:
virtual void set_cc_account_prestige(uint32_t id, uint64_t prestige) = 0;
virtual void grant_cc_account_unique_title(uint32_t id, const std::string &unique_title) = 0;
virtual void rescind_cc_account_unique_title(uint32_t id, const std::string &unique_title) = 0;
virtual void change_cc_account_keys(uint32_t id, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk) = 0;
virtual bool for_all_cc_accounts(std::function<bool(const cc_account_data_t&)>) const = 0;
virtual uint32_t allocate_new_cc_city(uint32_t seed, uint32_t mayor, const std::string &name, const std::string &tagline) = 0;
@ -2213,12 +2214,13 @@ public:
virtual bool for_all_cc_foreclosures(const std::function<bool(const cc::foreclosure_t&)> &f) const = 0;
virtual void remove_cc_foreclosure(uint32_t mortgage) = 0;
virtual uint32_t allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, const std::string &title, const std::string &description, uint32_t mortgage) = 0;
virtual uint32_t allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, uint64_t reserve_price, const std::string &title, const std::string &description, uint32_t mortgage) = 0;
virtual bool get_cc_auction_data(uint32_t auction, cc::auction_t &ad) const = 0;
virtual bool for_all_cc_auctions(const std::function<bool(const cc::auction_t&)> &f) const = 0;
virtual void remove_cc_auction(uint32_t id) = 0;
virtual void add_cc_auction_bid(uint32_t auction, uint32_t account, uint64_t price, uint64_t height) = 0;
virtual void add_cc_auction_bid(uint32_t auction, uint32_t account, const crypto::public_key &pkey, uint64_t price, uint64_t height) = 0;
virtual void remove_last_cc_auction_bid(uint32_t auction) = 0;
virtual void set_cc_auction_keys(uint32_t auction, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk) = 0;
virtual void set_cc_auction_ended(uint32_t auction, bool ended) = 0;
virtual void add_cc_runestone(const cc::runestone_t &runestone) = 0;
@ -2297,6 +2299,10 @@ public:
virtual void delete_last_cc_coru_tournament() = 0;
virtual bool for_all_cc_coru_tournaments(const std::function<bool(const cc::coru_tournament_state_t&)> &f, bool active_only = true) const = 0;
virtual void change_cc_trustee_balance(const crypto::public_key &pkey, int64_t delta_locked, int64_t delta_unlocked) = 0;
virtual std::pair<uint64_t, uint64_t> get_cc_trustee_balance(const crypto::public_key &pkey) const = 0;
virtual void get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances) const = 0;
virtual bool get_as_cc_account(const cryptonote::blobdata &bd, cc_account_data_t &data) const { return false; }
virtual bool get_as_cc_flag(const cryptonote::blobdata &bd, cc_flag_data_t &data) const { return false; }
virtual bool get_as_cc_city(const cryptonote::blobdata &bd, cc_city_data_t &data) const { return false; }

View File

@ -430,6 +430,7 @@ namespace
e cc_coru_requests nonce {request metadata}
* cc_coru_games id {coru metadata - id 0 ist a placeholder with the list of active games}
* cc_coru_tournaments id {tournament metadata - id 0 ist a placeholder with the list of active tournaments}
* cc_trustee_balances public_key balance
*
* 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"
@ -503,6 +504,7 @@ const char* const LMDB_CC_EPOCHS = "cc_epochs";
const char* const LMDB_CC_CORU_REQUESTS = "cc_coru_requests";
const char* const LMDB_CC_CORU_GAMES = "cc_coru_games";
const char* const LMDB_CC_CORU_TOURNAMENTS = "cc_coru_tournaments";
const char* const LMDB_CC_TRUSTEE_BALANCES = "cc_trustee_balances";
const char* const LMDB_PROPERTIES = "properties";
@ -1117,9 +1119,11 @@ typedef struct mdb_cc_auction_data_t
uint32_t mortgage;
uint64_t creation_height;
uint32_t base_ticks;
uint64_t reserve_price;
std::string title;
std::string description;
std::vector<std::tuple<uint32_t, uint64_t, uint64_t>> bids;
std::vector<std::tuple<uint32_t, crypto::public_key, uint64_t, uint64_t>> bids;
serializable_map<crypto::public_key, std::pair<crypto::public_key, crypto::public_key>> keys;
BEGIN_SERIALIZE_OBJECT()
VERSION_FIELD(0)
@ -1130,9 +1134,11 @@ typedef struct mdb_cc_auction_data_t
VARINT_FIELD(mortgage)
VARINT_FIELD(creation_height)
VARINT_FIELD(base_ticks)
VARINT_FIELD(reserve_price)
TEXT_FIELD(title)
TEXT_FIELD(description)
FIELD(bids)
FIELD(keys)
END_SERIALIZE()
} mdb_cc_auction_data_t;
@ -2625,6 +2631,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_CC_CORU_REQUESTS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT, m_cc_coru_requests, "Failed to open db handle for m_cc_coru_requests");
lmdb_db_open(txn, LMDB_CC_CORU_GAMES, MDB_CREATE, m_cc_coru_games, "Failed to open db handle for m_cc_coru_games");
lmdb_db_open(txn, LMDB_CC_CORU_TOURNAMENTS, MDB_CREATE, m_cc_coru_tournaments, "Failed to open db handle for m_cc_coru_tournaments");
lmdb_db_open(txn, LMDB_CC_TRUSTEE_BALANCES, MDB_CREATE, m_cc_trustee_balances, "Failed to open db handle for m_cc_trustee_balances");
lmdb_db_open(txn, LMDB_PROPERTIES, MDB_CREATE, m_properties, "Failed to open db handle for m_properties");
@ -2682,6 +2689,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_set_dupsort(txn, m_cc_coru_requests, compare_uint64);
mdb_set_compare(txn, m_cc_coru_games, compare_uint32);
mdb_set_compare(txn, m_cc_coru_tournaments, compare_uint32);
mdb_set_compare(txn, m_cc_trustee_balances, compare_hash32);
if (!(mdb_flags & MDB_RDONLY))
{
@ -2930,6 +2938,8 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_coru_games: ", result).c_str()));
if (auto result = mdb_drop(txn, m_cc_coru_tournaments, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_coru_tournaments: ", result).c_str()));
if (auto result = mdb_drop(txn, m_cc_trustee_balances, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_cc_trustee_balances: ", result).c_str()));
// init with current version
MDB_val_str(k, "version");
@ -7113,6 +7123,65 @@ void BlockchainLMDB::rescind_cc_account_unique_title(uint32_t id, const std::str
throw0(DB_ERROR(lmdb_error("Failed to add account data to db transaction: ", result).c_str()));
}
void BlockchainLMDB::change_cc_account_keys(uint32_t id, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(cc_accounts)
CURSOR(cc_account_keys)
// find account id
MDB_val_set(k, id);
MDB_val v;
int result = mdb_cursor_get(m_cur_cc_accounts, &k, &v, MDB_SET);
if (result)
throw0(DB_ERROR(lmdb_error("Account " + std::to_string(id) + " not found: ", result).c_str()));
mdb_cc_account_data ad;
if (!read_account_data(v, ad))
throw0(DB_ERROR("Failed to deserialize account data"));
crypto::public_key ff;
memset(&ff, 0xff, sizeof(ff));
if (ad.public_key != crypto::null_pkey && ad.public_key != ff)
{
MDB_val_set(v, ad.public_key);
result = mdb_cursor_get(m_cur_cc_account_keys, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to lookup account keys: ", result).c_str()));
result = mdb_cursor_del(m_cur_cc_account_keys, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to delete account keys: ", result).c_str()));
}
ad.public_key = pkey;
ad.pmspk = pmspk;
ad.pmvpk = pmvpk;
if (!write_account_data(v, ad))
throw0(DB_ERROR("Failed to serialize account data"));
result = mdb_cursor_put(m_cur_cc_accounts, &k, &v, 0);
if (v.mv_data) free(v.mv_data);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add account data to db transaction: ", result).c_str()));
if (ad.public_key != crypto::null_pkey && ad.public_key != ff)
{
mdb_cc_account_keys_data akd;
akd.public_key = ad.public_key;
akd.id = id;
v.mv_data = (void*)&akd;
v.mv_size = sizeof(akd);
result = mdb_cursor_put(m_cur_cc_account_keys, (MDB_val *)&zerokval, &v, MDB_NODUPDATA);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add account key data to db transaction: ", result).c_str()));
}
}
bool BlockchainLMDB::for_all_cc_accounts(std::function<bool(const cc_account_data_t &data)> f) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@ -11359,7 +11428,7 @@ void BlockchainLMDB::remove_cc_foreclosure(uint32_t mortgage)
static auto write_auction_data = write_data<mdb_cc_auction_data_t>;
static auto read_auction_data = read_data<mdb_cc_auction_data_t>;
uint32_t BlockchainLMDB::allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, const std::string &title, const std::string &description, uint32_t mortgage)
uint32_t BlockchainLMDB::allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, uint64_t reserve_price, const std::string &title, const std::string &description, uint32_t mortgage)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -11397,6 +11466,7 @@ uint32_t BlockchainLMDB::allocate_cc_auction(uint32_t seller, uint32_t type, con
ad.mortgage = mortgage;
ad.creation_height = height();
ad.base_ticks = base_ticks;
ad.reserve_price = reserve_price;
ad.title = title;
ad.description = description;
@ -11442,9 +11512,11 @@ bool BlockchainLMDB::get_cc_auction_data(uint32_t auction, cc::auction_t &cad) c
cad.mortgage = ad.mortgage;
cad.creation_height = ad.creation_height;
cad.base_ticks = ad.base_ticks;
cad.reserve_price = ad.reserve_price;
cad.title = ad.title;
cad.description = ad.description;
cad.bids = ad.bids;
cad.keys = ad.keys;
TXN_POSTFIX_RDONLY();
return true;
@ -11488,9 +11560,11 @@ bool BlockchainLMDB::for_all_cc_auctions(const std::function<bool(const cc::auct
auction.mortgage = ad.mortgage;
auction.creation_height = ad.creation_height;
auction.base_ticks = ad.base_ticks;
auction.reserve_price = ad.reserve_price;
auction.title = ad.title;
auction.description = ad.description;
auction.bids = ad.bids;
auction.keys = ad.keys;
if (!f(auction))
{
@ -11521,7 +11595,7 @@ void BlockchainLMDB::remove_cc_auction(uint32_t id)
throw1(DB_ERROR(lmdb_error("Error adding removal of auction to db transaction", result).c_str()));
}
void BlockchainLMDB::add_cc_auction_bid(uint32_t auction, uint32_t account, uint64_t price, uint64_t height)
void BlockchainLMDB::add_cc_auction_bid(uint32_t auction, uint32_t account, const crypto::public_key &pkey, uint64_t price, uint64_t height)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -11539,7 +11613,7 @@ void BlockchainLMDB::add_cc_auction_bid(uint32_t auction, uint32_t account, uint
if (!read_auction_data(v, ad))
throw0(DB_ERROR("Failed to serialize auction data"));
ad.bids.push_back(std::make_tuple(account, price, height));
ad.bids.push_back(std::make_tuple(account, pkey, price, height));
if (!write_auction_data(v, ad))
throw0(DB_ERROR("Failed to serialize auction data"));
@ -11608,6 +11682,37 @@ void BlockchainLMDB::set_cc_auction_ended(uint32_t auction, bool ended)
throw0(DB_ERROR(lmdb_error("Failed to set auction data in db transaction: ", result).c_str()));
}
void BlockchainLMDB::set_cc_auction_keys(uint32_t auction, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(cc_auctions)
MDB_val k = {sizeof(auction), (void *)&auction};
MDB_val v;
auto result = mdb_cursor_get(m_cur_cc_auctions, &k, &v, MDB_SET);
if (result != 0)
throw1(DB_ERROR(lmdb_error("Error finding auction", result).c_str()));
mdb_cc_auction_data_t ad;
if (!read_auction_data(v, ad))
throw0(DB_ERROR("Failed to serialize auction data"));
if (pmspk == crypto::null_pkey && pmvpk == crypto::null_pkey)
ad.keys.erase(pkey);
else
ad.keys[pkey] = std::make_pair(pmspk, pmvpk);
if (!write_auction_data(v, ad))
throw0(DB_ERROR("Failed to serialize auction data"));
result = mdb_cursor_put(m_cur_cc_auctions, &k, &v, 0);
if (v.mv_data) free(v.mv_data);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to set auction data in db transaction: ", result).c_str()));
}
static auto write_runestone_data = write_data<mdb_cc_runestone_data_t>;
static auto read_runestone_data = read_data<mdb_cc_runestone_data_t>;
@ -13823,6 +13928,108 @@ bool BlockchainLMDB::for_all_cc_coru_tournaments(const std::function<bool(const
return ret;
}
void BlockchainLMDB::change_cc_trustee_balance(const crypto::public_key &pkey, int64_t delta_locked, int64_t delta_unlocked)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
if (delta_locked == 0 && delta_unlocked == 0)
return;
CURSOR(cc_trustee_balances)
MDB_val k, v;
k.mv_data = (void*)&pkey;
k.mv_size = sizeof(pkey);
int result = mdb_cursor_get(m_cur_cc_trustee_balances, &k, &v, MDB_SET);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to lookup trustee balance: ", result).c_str()));
if (result == 0 && v.mv_size != 2 * sizeof(uint64_t))
throw0(DB_ERROR("Trustee balance has unexpected size"));
uint64_t locked = result == MDB_NOTFOUND ? 0 : ((uint64_t*)v.mv_data)[0];
uint64_t unlocked = result == MDB_NOTFOUND ? 0 : ((uint64_t*)v.mv_data)[1];
if (delta_locked > 0 && locked > std::numeric_limits<uint64_t>::max() - delta_locked)
throw0(DB_ERROR("Trustee balance overflow"));
else if (delta_locked < 0 && locked < (uint64_t)-delta_locked)
throw0(DB_ERROR("Trustee balance underflow"));
locked += delta_locked;
if (delta_unlocked > 0 && unlocked > std::numeric_limits<uint64_t>::max() - delta_unlocked)
throw0(DB_ERROR("Trustee balance overflow"));
else if (delta_unlocked < 0 && unlocked < (uint64_t)-delta_unlocked)
throw0(DB_ERROR("Trustee balance underflow"));
unlocked += delta_unlocked;
if (locked == 0 && unlocked == 0)
{
result = mdb_cursor_del(m_cur_cc_trustee_balances, 0);
}
else
{
uint64_t data[2] = { locked, unlocked };
v.mv_data = (void*)data;
v.mv_size = sizeof(data);
result = mdb_cursor_put(m_cur_cc_trustee_balances, &k, &v, 0);
}
if (result)
throw0(DB_ERROR(lmdb_error("Failed to write trustee balance: ", result).c_str()));
}
std::pair<uint64_t, uint64_t> BlockchainLMDB::get_cc_trustee_balance(const crypto::public_key &pkey) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(cc_trustee_balances)
MDB_val k = {sizeof(pkey), (void *)&pkey};
MDB_val v;
auto result = mdb_cursor_get(m_cur_cc_trustee_balances, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
return std::pair<uint64_t, uint64_t>(0, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to lookup trustee balance: ", result).c_str()));
if (v.mv_size != 2 * sizeof(uint64_t))
throw0(DB_ERROR("Trustee balance has unexpected size"));
const uint64_t locked = ((const uint64_t*)v.mv_data)[0];
const uint64_t unlocked = ((const uint64_t*)v.mv_data)[1];
return std::make_pair(locked, unlocked);
}
void BlockchainLMDB::get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(cc_trustee_balances)
balances.clear();
MDB_val k, v;
MDB_cursor_op op = MDB_FIRST;
while (1)
{
int result = mdb_cursor_get(m_cur_cc_trustee_balances, &k, &v, op);
op = MDB_NEXT;
if (result == MDB_NOTFOUND)
break;
if (result)
throw0(DB_ERROR(lmdb_error("Failed to enumerate trustee balances: ", result).c_str()));
if (v.mv_size != 2 * sizeof(uint64_t))
throw0(DB_ERROR("Trustee balance has unexpected size"));
const crypto::public_key pkey = *(const crypto::public_key*)k.mv_data;
const uint64_t locked = ((const uint64_t*)v.mv_data)[0];
const uint64_t unocked = ((const uint64_t*)v.mv_data)[1];
balances[pkey] = std::make_pair(locked, unocked);
}
TXN_POSTFIX_RDONLY();
}
uint64_t BlockchainLMDB::get_database_size() const
{
uint64_t size = 0;

View File

@ -113,6 +113,7 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_cc_coru_requests;
MDB_cursor *m_txc_cc_coru_games;
MDB_cursor *m_txc_cc_coru_tournaments;
MDB_cursor *m_txc_cc_trustee_balances;
} mdb_txn_cursors;
#define m_cur_blocks m_cursors->m_txc_blocks
@ -172,6 +173,7 @@ typedef struct mdb_txn_cursors
#define m_cur_cc_coru_requests m_cursors->m_txc_cc_coru_requests
#define m_cur_cc_coru_games m_cursors->m_txc_cc_coru_games
#define m_cur_cc_coru_tournaments m_cursors->m_txc_cc_coru_tournaments
#define m_cur_cc_trustee_balances m_cursors->m_txc_cc_trustee_balances
typedef struct mdb_rflags
{
@ -233,6 +235,7 @@ typedef struct mdb_rflags
bool m_rf_cc_coru_requests;
bool m_rf_cc_coru_games;
bool m_rf_cc_coru_tournaments;
bool m_rf_cc_trustee_balances;
} mdb_rflags;
typedef struct mdb_threadinfo
@ -585,6 +588,7 @@ private:
void set_cc_account_prestige(uint32_t id, uint64_t prestige);
void grant_cc_account_unique_title(uint32_t id, const std::string &unique_title);
void rescind_cc_account_unique_title(uint32_t id, const std::string &unique_title);
void change_cc_account_keys(uint32_t id, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk);
bool for_all_cc_accounts(std::function<bool(const cc_account_data_t&)>) const;
uint32_t allocate_new_cc_city(uint32_t seed, uint32_t mayor, const std::string &name, const std::string &tagline);
@ -717,12 +721,13 @@ private:
virtual bool for_all_cc_foreclosures(const std::function<bool(const cc::foreclosure_t&)> &f) const;
virtual void remove_cc_foreclosure(uint32_t mortgage);
virtual uint32_t allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, const std::string &title, const std::string &description, uint32_t mortgage);
virtual uint32_t allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, uint64_t reserve_price, const std::string &title, const std::string &description, uint32_t mortgage);
virtual bool get_cc_auction_data(uint32_t auction, cc::auction_t &ad) const;
virtual bool for_all_cc_auctions(const std::function<bool(const cc::auction_t&)> &f) const;
virtual void remove_cc_auction(uint32_t id);
virtual void add_cc_auction_bid(uint32_t auction, uint32_t account, uint64_t price, uint64_t height);
virtual void add_cc_auction_bid(uint32_t auction, uint32_t account, const crypto::public_key &pkey, uint64_t price, uint64_t height);
virtual void remove_last_cc_auction_bid(uint32_t auction);
virtual void set_cc_auction_keys(uint32_t auction, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk);
virtual void set_cc_auction_ended(uint32_t auction, bool ended);
virtual void add_cc_runestone(const cc::runestone_t &runestone);
@ -801,6 +806,10 @@ private:
virtual void delete_last_cc_coru_tournament();
virtual bool for_all_cc_coru_tournaments(const std::function<bool(const cc::coru_tournament_state_t&)> &f, bool active_only = true) const;
virtual void change_cc_trustee_balance(const crypto::public_key &pkey, int64_t delta_locked, int64_t delta_unlocked);
virtual std::pair<uint64_t, uint64_t> get_cc_trustee_balance(const crypto::public_key &pkey) const;
virtual void get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances) const;
virtual bool get_as_cc_account(const cryptonote::blobdata &bd, cc_account_data_t &data) const;
virtual bool get_as_cc_flag(const cryptonote::blobdata &bd, cc_flag_data_t &data) const;
virtual bool get_as_cc_city(const cryptonote::blobdata &bd, cc_city_data_t &data) const;
@ -904,6 +913,7 @@ private:
MDB_dbi m_cc_coru_requests;
MDB_dbi m_cc_coru_games;
MDB_dbi m_cc_coru_tournaments;
MDB_dbi m_cc_trustee_balances;
mutable uint64_t m_cum_size; // used in batch size estimation
mutable unsigned int m_cum_count;

View File

@ -204,6 +204,7 @@ public:
virtual void set_cc_account_prestige(uint32_t id, uint64_t prestige) {}
virtual void grant_cc_account_unique_title(uint32_t id, const std::string &unique_title) {}
virtual void rescind_cc_account_unique_title(uint32_t id, const std::string &unique_title) {}
virtual void change_cc_account_keys(uint32_t id, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk) {}
virtual bool for_all_cc_accounts(std::function<bool(const cc_account_data_t&)>) const { return true; }
virtual uint32_t allocate_new_cc_city(uint32_t seed, uint32_t mayor, const std::string &name, const std::string &tagline) { return 0; }
@ -336,12 +337,13 @@ public:
virtual bool for_all_cc_foreclosures(const std::function<bool(const cc::foreclosure_t&)> &f) const { return false; }
virtual void remove_cc_foreclosure(uint32_t mortgage) {}
virtual uint32_t allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, const std::string &title, const std::string &description, uint32_t mortgage) { return 1; }
virtual uint32_t allocate_cc_auction(uint32_t seller, uint32_t type, const std::vector<std::pair<uint32_t, uint32_t>> &entries, uint32_t base_ticks, uint64_t reserve_price, const std::string &title, const std::string &description, uint32_t mortgage) { return 1; }
virtual bool get_cc_auction_data(uint32_t auction, cc::auction_t &ad) const { return false; }
virtual bool for_all_cc_auctions(const std::function<bool(const cc::auction_t&)> &f) const { return true; }
virtual void remove_cc_auction(uint32_t id) {}
virtual void add_cc_auction_bid(uint32_t auction, uint32_t account, uint64_t price, uint64_t height) {}
virtual void add_cc_auction_bid(uint32_t auction, uint32_t account, const crypto::public_key &pkey, uint64_t price, uint64_t height) {}
virtual void remove_last_cc_auction_bid(uint32_t auction) {}
virtual void set_cc_auction_keys(uint32_t auction, const crypto::public_key &pkey, const crypto::public_key &pmspk, const crypto::public_key &pmvpk) {}
virtual void set_cc_auction_ended(uint32_t auction, bool ended) {}
virtual void add_cc_runestone(const cc::runestone_t &runestone) {}
@ -420,6 +422,10 @@ public:
virtual void delete_last_cc_coru_tournament() {}
virtual bool for_all_cc_coru_tournaments(const std::function<bool(const cc::coru_tournament_state_t&)> &f, bool active_only = true) const { return true; }
virtual void change_cc_trustee_balance(const crypto::public_key &pkey, int64_t delta_locked, int64_t delta_unlocked) {}
virtual std::pair<uint64_t, uint64_t> get_cc_trustee_balance(const crypto::public_key &pkey) const { return std::make_pair(0, 0); }
virtual void get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances) const {}
private:
uint32_t n_accounts;
};

View File

@ -655,6 +655,7 @@ int main(int argc, char* argv[])
copy_table(env0, env1, "cc_coru_requests", MDB_DUPSORT, 0, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "cc_coru_games", 0, 0, BlockchainLMDB::compare_uint32);
copy_table(env0, env1, "cc_coru_tournaments", 0, 0, BlockchainLMDB::compare_uint32);
copy_table(env0, env1, "cc_trustee_balances", 0, 0, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "properties", 0, 0, BlockchainLMDB::compare_string);
if (already_pruned)
{

View File

@ -33,6 +33,7 @@ ADD_FLEX_BISON_DEPENDENCY(lexer parser)
set(cc_sources
cc_command_handler_helpers.cpp
cc_command_handler_coru_helpers.cpp
cc_command_handler_account_auction_bid.cpp
cc_command_handler_add_city_specialization.cpp
cc_command_handler_allow_settlers.cpp
cc_command_handler_allow_styling.cpp
@ -109,6 +110,7 @@ set(cc_sources
cc_command_handler_upgrade_building.cpp
cc_command_handler_update_item.cpp
cc_command_handler_whisper.cpp
cc_command_handler_withdraw_trustee_balance.cpp
cc_auction.cc
cc_badge.cpp
cc_blockchain_state_proxy.cpp
@ -152,6 +154,7 @@ set(cc_sources
set(cc_headers
cc_command_handler_helpers.h
cc_command_handler_coru_helpers.h
cc_command_handler_account_auction_bid.h
cc_command_handler_add_city_specialization.h
cc_command_handler_allow_styling.h
cc_command_handler_assign_items.h
@ -227,6 +230,7 @@ set(cc_headers
cc_command_handler_upgrade_building.h
cc_command_handler_update_item.h
cc_command_handler_whisper.h
cc_command_handler_withdraw_trustee_balance.h
cc_auction.h
cc_badge.h
cc_blockchain_state_proxy.h

View File

@ -42,6 +42,7 @@
#include "lz4.h"
#include "coru.h"
#include "coru-coins-and-runes.h"
#include "cc_command_handler_account_auction_bid.h"
#include "cc_command_handler_add_city_specialization.h"
#include "cc_command_handler_allow_settlers.h"
#include "cc_command_handler_allow_styling.h"
@ -118,6 +119,7 @@
#include "cc_command_handler_update_item.h"
#include "cc_command_handler_upgrade_building.h"
#include "cc_command_handler_whisper.h"
#include "cc_command_handler_withdraw_trustee_balance.h"
#include "cc_potential.h"
#include "cc_influence.h"
#include "cc_discoveries.h"
@ -4273,6 +4275,7 @@ static cc_command_handler &get_cc_command_handler(const cryptonote::cc_command_t
{
struct visitor: public boost::static_visitor<cc_command_handler&>
{
cc_command_handler &operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return cc_command_handler_account_auction_bid::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return cc_command_handler_add_city_specialization::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return cc_command_handler_allow_settlers::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return cc_command_handler_allow_styling::instance; }
@ -4349,6 +4352,7 @@ static cc_command_handler &get_cc_command_handler(const cryptonote::cc_command_t
cc_command_handler &operator()(const cryptonote::cc_command_update_item_t &cmd) const { return cc_command_handler_update_item::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return cc_command_handler_upgrade_building::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_whisper_t &cmd) const { return cc_command_handler_whisper::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return cc_command_handler_withdraw_trustee_balance::instance; }
};
return boost::apply_visitor(visitor(), cmd);
}

View File

@ -2,13 +2,15 @@
#include <stdint.h>
#include <vector>
#include <map>
#include "crypto/crypto.h"
namespace cc
{
struct auction_t
{
enum { type_flag, type_item };
enum { type_flag, type_item, type_account };
uint32_t id;
uint32_t seller;
@ -17,9 +19,11 @@ struct auction_t
uint32_t mortgage;
uint64_t creation_height;
uint32_t base_ticks;
uint64_t reserve_price;
std::string title;
std::string description;
std::vector<std::tuple<uint32_t, uint64_t, uint64_t>> bids; // account, price, height
std::vector<std::tuple<uint32_t, crypto::public_key, uint64_t, uint64_t>> bids; // account, price, height
std::map<crypto::public_key, std::pair<crypto::public_key, crypto::public_key>> keys;
bool operator==(const auction_t &other) const {
return id == other.id
@ -29,9 +33,11 @@ struct auction_t
&& mortgage == other.mortgage
&& creation_height == other.creation_height
&& base_ticks == other.base_ticks
&& reserve_price == other.reserve_price
&& title == other.title
&& description == other.description
&& bids == other.bids
&& keys == other.keys
;
}
};

View File

@ -0,0 +1,146 @@
// Copyright (c) 2019, 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 "cc/cc_config.h"
#include "cc/cc.h"
#include "blockchain_db/blockchain_db.h"
#include "cc_command_handler_helpers.h"
#include "cc_command_handler_account_auction_bid.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "verify"
namespace cc
{
cc_command_handler_account_auction_bid cc_command_handler_account_auction_bid::instance;
void cc_command_handler_account_auction_bid::get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const
{
const cryptonote::cc_command_account_auction_bid_t &account_auction_bid = boost::get<cryptonote::cc_command_account_auction_bid_t>(cmd);
cc_in = 0;
cc_out = account_auction_bid.price_increase;
}
uint64_t cc_command_handler_account_auction_bid::get_cost(const cryptonote::cc_command_t &cmd) const
{
return 0;
}
bool cc_command_handler_account_auction_bid::check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, cryptonote::tx_verification_context &tvc) const
{
const cryptonote::cc_command_account_auction_bid_t &account_auction_bid = boost::get<cryptonote::cc_command_account_auction_bid_t>(cmd);
cc::auction_t auction;
CHECK_COMMAND_SET(account_auction_bid.pkey != crypto::null_pkey, tvc, m_cc_invalid_account, "Invalid public key");
CHECK_COMMAND_SET(account_auction_bid.price_increase > AUCTION_BID_FEE, tvc, m_cc_bad_price, "Price must be greater than the auction bid fee ");
CHECK_COMMAND_SET(account_auction_bid.price_increase <= std::numeric_limits<int64_t>::max(), tvc, m_cc_bad_price, "Price increase too high");
CHECK_COMMAND_SET(db.get_cc_auction_data(account_auction_bid.auction, auction), tvc, m_cc_invalid_auction, "Auction not found");
CHECK_COMMAND_SET(auction.type == cc::auction_t::type_account, tvc, m_cc_invalid_auction, "External bids are only allowed for account auctions");
uint64_t last_bid = 0;
for (const auto &e: auction.bids)
if (std::get<0>(e) == 0 && std::get<1>(e) == account_auction_bid.pkey)
last_bid = std::get<2>(e);
const uint64_t price_increase = account_auction_bid.price_increase - AUCTION_BID_FEE;
CHECK_COMMAND_SET(price_increase <= std::numeric_limits<uint64_t>::max() - last_bid, tvc, m_cc_overflow, "Overflow");
uint64_t new_bid = last_bid + price_increase;
CHECK_COMMAND_SET(auction.bids.empty() || new_bid > std::get<2>(auction.bids.back()), tvc, m_cc_bad_price, "Price is not higher than current highest bid");
// keys must be be present for the first bid only
if (account_auction_bid.pm_keys)
{
CHECK_COMMAND_SET(account_auction_bid.pmspk != crypto::null_pkey, tvc, m_cc_keys, "Invalid pmspk");
CHECK_COMMAND_SET(account_auction_bid.pmvpk != crypto::null_pkey, tvc, m_cc_keys, "Invalid pmvpk");
// we abuse the original pmspk to store the original account pubkey, so make sure it's not used
// as a buyer's pubkey
cryptonote::cc_account_data_t ad;
CHECK_COMMAND_SET(db.get_cc_account_data(auction.entries[0].first, ad), tvc, m_cc_invalid_account, "Failed to get account data");
CHECK_COMMAND_SET(account_auction_bid.pkey != ad.pmspk, tvc, m_cc_keys, "Buyer pubkey is original account's message key");
CHECK_COMMAND_SET(account_auction_bid.pkey != ad.pmvpk, tvc, m_cc_keys, "Buyer pubkey is original account's message key");
}
const bool first_bid = last_bid == 0;
CHECK_COMMAND_SET(account_auction_bid.pm_keys == first_bid, tvc, m_cc_keys, "Keys must be supplied for the first bid for an account, and only then");
// the key must not be used for an account already
uint32_t account_id = 0;
CHECK_COMMAND_SET(!db.lookup_cc_account(account_auction_bid.pkey, account_id) || account_id == 0, tvc, m_cc_invalid_account,
"An account auction may only be bid on from a wallet which does not already have a game account");
return true;
}
bool cc_command_handler_account_auction_bid::execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, uint64_t tx_fee, game_events_t &events) const
{
const cryptonote::cc_command_account_auction_bid_t &account_auction_bid = boost::get<cryptonote::cc_command_account_auction_bid_t>(cmd);
cc::auction_t auction;
CHECK_AND_ASSERT_MES(db.get_cc_auction_data(account_auction_bid.auction, auction), false, "Auction not found");
uint64_t last_bid = 0;
for (const auto &e: auction.bids)
if (std::get<0>(e) == 0 && std::get<1>(e) == account_auction_bid.pkey)
last_bid = std::get<2>(e);
const uint64_t price_increase = account_auction_bid.price_increase - AUCTION_BID_FEE;
CHECK_AND_ASSERT_MES(price_increase <= std::numeric_limits<uint64_t>::max() - last_bid, false, "Overflow");
uint64_t new_bid = last_bid + price_increase;
db.add_cc_auction_bid(account_auction_bid.auction, 0, account_auction_bid.pkey, new_bid, db.height());
if (account_auction_bid.pm_keys)
db.set_cc_auction_keys(account_auction_bid.auction, account_auction_bid.pkey, account_auction_bid.pmspk, account_auction_bid.pmvpk);
db.change_cc_trustee_balance(account_auction_bid.pkey, price_increase, 0);
std::map<uint32_t, int64_t> balance_changes;
CHECK_AND_ASSERT_MES(cc::distribute_to_treasuries(db, AUCTION_BID_FEE, false, &balance_changes), false, "Failed to distribute to treasuries");
for (const auto &e: balance_changes)
events.add_full(cmd, e.first, 0, 0, ITEM_NONE, 0, e.second, 0) << "Received auction bid fee";
return true;
}
bool cc_command_handler_account_auction_bid::revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version) const
{
const cryptonote::cc_command_account_auction_bid_t &account_auction_bid = boost::get<cryptonote::cc_command_account_auction_bid_t>(cmd);
cc::auction_t auction;
CHECK_AND_ASSERT_MES(cc::distribute_to_treasuries(db, AUCTION_BID_FEE, true), false, "Failed to distribute from treasuries");
db.remove_last_cc_auction_bid(account_auction_bid.auction);
const uint64_t price_increase = account_auction_bid.price_increase - AUCTION_BID_FEE;
db.change_cc_trustee_balance(account_auction_bid.pkey, -(int64_t)price_increase, 0);
if (account_auction_bid.pm_keys)
db.set_cc_auction_keys(account_auction_bid.auction, account_auction_bid.pkey, crypto::null_pkey, crypto::null_pkey);
return true;
}
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2019, 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.
#pragma once
#include "cc_command_handler.h"
namespace cc
{
class cc_command_handler_account_auction_bid: public cc_command_handler
{
public:
virtual void get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const;
virtual uint64_t get_cost(const cryptonote::cc_command_t &cmd) const;
virtual bool check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, cryptonote::tx_verification_context &tvc) const;
virtual bool execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, uint64_t tx_fee, game_events_t &events) const;
virtual bool revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version) const;
static cc_command_handler_account_auction_bid instance;
};
}

View File

@ -62,11 +62,13 @@ bool cc_command_handler_auction_bid::check(const cryptonote::BlockchainDB &db, c
CHECK_COMMAND_SET(auction_bid.price > 0, tvc, m_cc_bad_price, "Price is zero");
CHECK_COMMAND_SET(auction_bid.price <= std::numeric_limits<uint64_t>::max() - AUCTION_BID_FEE, tvc, m_cc_overflow, "Overflow");
CHECK_COMMAND_SET(db.get_cc_auction_data(auction_bid.auction, auction), tvc, m_cc_invalid_auction, "Auction not found");
CHECK_COMMAND_SET(auction.bids.empty() || auction_bid.price > std::get<1>(auction.bids.back()), tvc, m_cc_bad_price, "Price is not higher than current highest bid");
CHECK_COMMAND_SET(auction.type != cc::auction_t::type_account, tvc, m_cc_out_of_range, "Normal bid commands may not be used for account auctions");
CHECK_COMMAND_SET(auction_bid.price >= auction.reserve_price, tvc, m_cc_bad_price, "Price is below reserve price");
CHECK_COMMAND_SET(auction.bids.empty() || auction_bid.price > std::get<2>(auction.bids.back()), tvc, m_cc_bad_price, "Price is not higher than current highest bid");
CHECK_COMMAND_SET(db.get_cc_account_data(auction_bid.cc_account, ad), tvc, m_cc_invalid_account, "Failed to get account data");
for (const auto &e: auction.bids)
if (std::get<0>(e) == auction_bid.cc_account)
current_bid = std::get<1>(e);
current_bid = std::get<2>(e);
CHECK_COMMAND_SET(auction_bid.price > current_bid, tvc, m_cc_bad_price, "Price is no higher than highest bid from this account");
CHECK_COMMAND_SET(auction_bid.price - current_bid + AUCTION_BID_FEE <= ad.balance, tvc, m_cc_balance, "Not enough money to bid");
@ -98,11 +100,11 @@ bool cc_command_handler_auction_bid::execute(cryptonote::BlockchainDB &db, const
if (!auction.bids.empty())
{
const uint32_t bidder = std::get<0>(auction.bids.back());
const uint64_t amount = std::get<1>(auction.bids.back());
const uint64_t amount = std::get<2>(auction.bids.back());
db.unreserve_cc_account_balance(bidder, FORECLOSURE_ACCOUNT, amount);
}
db.reserve_cc_account_balance(auction_bid.cc_account, FORECLOSURE_ACCOUNT, auction_bid.price);
db.add_cc_auction_bid(auction_bid.auction, auction_bid.cc_account, auction_bid.price, db.height());
db.add_cc_auction_bid(auction_bid.auction, auction_bid.cc_account, crypto::null_pkey, auction_bid.price, db.height());
events.add_full(cmd, auction_bid.cc_account, 0, 0, ITEM_NONE, 0, -(int64_t)AUCTION_BID_FEE, tx_fee) << "Bid on auction";
@ -123,12 +125,12 @@ bool cc_command_handler_auction_bid::revert(cryptonote::BlockchainDB &db, const
CHECK_AND_ASSERT_MES(db.change_cc_account_balance(auction_bid.cc_account, AUCTION_BID_FEE), false, "Balance would overflow");
db.unreserve_cc_account_balance(auction_bid.cc_account, FORECLOSURE_ACCOUNT, auction_bid.price);
CHECK_AND_ASSERT_MES(cc::distribute_to_treasuries(db, AUCTION_BID_FEE, true), false, "Failed to distribute from treasuries");
db.remove_cc_auction_bid(auction_bid.auction, auction_bid.cc_account, auction_bid.price, db.height());
db.remove_last_cc_auction_bid(auction_bid.auction);
auction.bids.pop_back();
if (!auction.bids.empty())
{
const uint32_t bidder = std::get<0>(auction.bids.back());
const uint64_t amount = std::get<1>(auction.bids.back());
const uint64_t amount = std::get<2>(auction.bids.back());
db.reserve_cc_account_balance(bidder, FORECLOSURE_ACCOUNT, amount);
}

View File

@ -109,6 +109,11 @@ bool cc_command_handler_create_auction::check(const cryptonote::BlockchainDB &db
}
break;
}
case cc::auction_t::type_account:
CHECK_COMMAND_SET(create_auction.entries.size() == 1, tvc, m_cc_out_of_range, "Only one account may be auctioned at a time");
CHECK_COMMAND_SET(create_auction.entries[0].object == create_auction.cc_account, tvc, m_cc_bad_item, "Account auction may only sell the auctioning account");
CHECK_COMMAND_SET(create_auction.entries[0].amount == 1, tvc, m_cc_bad_amount, "Account auction may only sell a simgle account");
break;
default:
tvc.m_cc_invalid_auction = true;
tvc.error = "Invalid auction type";
@ -148,7 +153,7 @@ bool cc_command_handler_create_auction::execute(cryptonote::BlockchainDB &db, co
std::vector<std::pair<uint32_t, uint32_t>> entries;
for (const auto &e: create_auction.entries)
entries.push_back(std::make_pair(e.object, e.amount));
const uint32_t id = db.allocate_cc_auction(create_auction.cc_account, create_auction.type, entries, create_auction.base_ticks, create_auction.title, create_auction.description, 0);
const uint32_t id = db.allocate_cc_auction(create_auction.cc_account, create_auction.type, entries, create_auction.base_ticks, create_auction.reserve_price, create_auction.title, create_auction.description, 0);
CHECK_AND_ASSERT_MES(id != 0, false, "Failed to allocate new auction");
CHECK_AND_ASSERT_MES(db.change_cc_account_balance(create_auction.cc_account, -(int64_t)NEW_AUCTION_FEE), false, "Balance would underflow");
@ -186,6 +191,22 @@ bool cc_command_handler_create_auction::execute(cryptonote::BlockchainDB &db, co
events.add_full(cmd, create_auction.cc_account, 0, 0, std::move(entries), -(int64_t)NEW_AUCTION_FEE, tx_fee) << "Auctioned " << item_string;
}
break;
case cc::auction_t::type_account:
{
// abuse dummy keys 0 and fff... to backup original account keys for revert purposes
cryptonote::cc_account_data_t ad;
CHECK_AND_ASSERT_MES(db.get_cc_account_data(create_auction.cc_account, ad), false, "Failed to get account data");
db.set_cc_auction_keys(id, crypto::null_pkey, ad.public_key, crypto::null_pkey);
crypto::public_key ff;
memset(&ff, 0xff, sizeof(ff));
db.set_cc_auction_keys(id, ff, ad.pmspk, ad.pmvpk);
memset(&ad.public_key, 0xff, sizeof(ad.public_key));
memset(&ad.pmspk, 0xff, sizeof(ad.pmspk));
memset(&ad.pmvpk, 0xff, sizeof(ad.pmvpk));
db.change_cc_account_keys(create_auction.cc_account, ff, ff, ff);
events.add_full(cmd, create_auction.cc_account, 0, 0, ITEM_NONE, 0, -(int64_t)NEW_AUCTION_FEE, tx_fee) << "Auctioned account";
}
break;
default:
MERROR("Invalid auction type");
return false;
@ -201,6 +222,28 @@ bool cc_command_handler_create_auction::revert(cryptonote::BlockchainDB &db, con
CHECK_AND_ASSERT_MES(db.change_cc_account_balance(create_auction.cc_account, NEW_AUCTION_FEE), false, "Balancw would overflow");
CHECK_AND_ASSERT_MES(cc::distribute_to_treasuries(db, NEW_AUCTION_FEE, true), false, "Failed to distribute from treasuries");
uint32_t id = 0;
db.for_all_cc_auctions([&](const cc::auction_t &auction) {
if (auction.seller == create_auction.cc_account && auction.type == create_auction.type && auction.entries == create_auction.entries && auction.title == create_auction.title && auction.description == create_auction.description && auction.mortgage == 0)
id = auction.id; // last auction that matches, so do not return here
return true;
});
CHECK_AND_ASSERT_MES(id != 0, false, "Failed to find auction");
if (create_auction.type == cc::auction_t::type_account)
{
cc::auction_t aucd;
CHECK_AND_ASSERT_MES(db.get_cc_auction_data(id, aucd), false, "Failed to get auction data");
const auto i = aucd.keys.find(crypto::null_pkey);
CHECK_AND_ASSERT_MES(i != aucd.keys.end(), false, "No original account keys");
crypto::public_key ff;
memset(&ff, 0xff, sizeof(ff));
const auto j = aucd.keys.find(ff);
CHECK_AND_ASSERT_MES(j != aucd.keys.end(), false, "No original account keys");
db.change_cc_account_keys(create_auction.cc_account, i->second.first, j->second.first, j->second.second);
}
if (create_auction.type == cc::auction_t::type_item)
{
std::map<uint32_t, uint32_t> reserved_owner_items, reserved_items;
@ -209,13 +252,6 @@ bool cc_command_handler_create_auction::revert(cryptonote::BlockchainDB &db, con
db.unreserve_cc_account(create_auction.cc_account, FORECLOSURE_ACCOUNT, 0, reserved_items);
}
uint32_t id = 0;
db.for_all_cc_auctions([&](const cc::auction_t &auction) {
if (auction.seller == create_auction.cc_account && auction.type == create_auction.type && auction.entries == create_auction.entries && auction.title == create_auction.title && auction.description == create_auction.description && auction.mortgage == 0)
id = auction.id; // last auction that matches, so do not return here
return true;
});
CHECK_AND_ASSERT_MES(id != 0, false, "Failed to find auction");
db.remove_cc_auction(id);
CHECK_AND_ASSERT_MES(db.change_cc_account_num_auctions_created(create_auction.cc_account, -1), false, "Failed to update num_auctions_created");

View File

@ -445,10 +445,12 @@ bool cc_command_handler_game_update::execute(cryptonote::BlockchainDB &db, const
cc::auction_t ad;
CHECK_AND_ASSERT_MES(db.get_cc_auction_data(e, ad), false, "Failed to get auction data");
if (!ad.bids.empty())
db.unreserve_cc_account_balance(std::get<0>(ad.bids.back()), FORECLOSURE_ACCOUNT, std::get<1>(ad.bids.back()));
if (ad.type != cc::auction_t::type_account)
if (!ad.bids.empty())
db.unreserve_cc_account_balance(std::get<0>(ad.bids.back()), FORECLOSURE_ACCOUNT, std::get<2>(ad.bids.back()));
const uint32_t buyer = ad.bids.empty() ? ad.seller : std::get<0>(ad.bids.back());
const uint64_t price = ad.bids.empty() ? 0 : std::get<2>(ad.bids.back());
switch (ad.type)
{
case cc::auction_t::type_flag:
@ -483,6 +485,23 @@ bool cc_command_handler_game_update::execute(cryptonote::BlockchainDB &db, const
db.unreserve_cc_account(ad.seller, FORECLOSURE_ACCOUNT, 0, reserved_items);
break;
}
case cc::auction_t::type_account:
{
// change keys, move winning bid to trust, unlock all in trust
std::map<crypto::public_key, uint64_t> last_bids;
for (const auto &e: ad.bids)
last_bids[std::get<1>(e)] = std::get<2>(e);
for (const auto &e: last_bids)
db.change_cc_trustee_balance(e.first, -(int64_t)e.second, (int64_t)e.second);
db.change_cc_trustee_balance(std::get<1>(ad.bids.back()), 0, -(int64_t)price);
const crypto::public_key &seller_pkey = ad.keys[crypto::null_pkey].first;
db.change_cc_trustee_balance(seller_pkey, 0, (int64_t)price);
const auto i = ad.keys.find(std::get<1>(ad.bids.back()));
CHECK_AND_ASSERT_MES(i != ad.keys.end(), false, "Buyer keys not found");
db.change_cc_account_keys(ad.seller, i->first, i->second.first, i->second.second);
break;
}
default:
MERROR("Invalid auction type");
return false;
@ -590,7 +609,7 @@ bool cc_command_handler_game_update::execute(cryptonote::BlockchainDB &db, const
std::vector<std::pair<uint32_t, uint32_t>> entries;
entries.push_back(std::make_pair(flag, 1));
db.allocate_cc_auction(cid.creator, cc::auction_t::type_flag, std::move(entries), MORTGAGE_AUCTION_BASE_TICKS, "", "Automatic auction upon mortgage repayment default", e.mortgage);
db.allocate_cc_auction(cid.creator, cc::auction_t::type_flag, std::move(entries), MORTGAGE_AUCTION_BASE_TICKS, 0, "", "Automatic auction upon mortgage repayment default", e.mortgage);
}
uint32_t expected_coru_account = 1;
@ -1106,8 +1125,10 @@ bool cc_command_handler_game_update::revert(cryptonote::BlockchainDB &db, const
cc::auction_t ad;
db.set_cc_auction_ended(e, false);
CHECK_AND_ASSERT_MES(db.get_cc_auction_data(e, ad), false, "Failed to get auction data");
if (!ad.bids.empty())
db.reserve_cc_account_balance(std::get<0>(ad.bids.back()), FORECLOSURE_ACCOUNT, std::get<1>(ad.bids.back()));
if (ad.type != cc::auction_t::type_account)
if (!ad.bids.empty())
db.reserve_cc_account_balance(std::get<0>(ad.bids.back()), FORECLOSURE_ACCOUNT, std::get<2>(ad.bids.back()));
switch (ad.type)
{
@ -1138,6 +1159,28 @@ bool cc_command_handler_game_update::revert(cryptonote::BlockchainDB &db, const
db.reserve_cc_account(ad.seller, FORECLOSURE_ACCOUNT, 0, reserved_items);
break;
}
case cc::auction_t::type_account:
{
// change keys, move winning bid to trust, unlock all in trust
const auto i = ad.keys.find(crypto::null_pkey);
CHECK_AND_ASSERT_MES(i != ad.keys.end(), false, "No original account keys");
const crypto::public_key seller_public_key = i->second.first;
crypto::public_key ff;
memset(&ff, 0xff, sizeof(ff));
db.change_cc_account_keys(ad.seller, ff, ff, ff);
const uint64_t price = ad.bids.empty() ? 0 : std::get<2>(ad.bids.back());
db.change_cc_trustee_balance(seller_public_key, 0, -(int64_t)price);
db.change_cc_trustee_balance(std::get<1>(ad.bids.back()), 0, (int64_t)price);
std::map<crypto::public_key, uint64_t> last_bids;
for (const auto &e: ad.bids)
last_bids[std::get<1>(e)] = std::get<2>(e);
for (const auto &e: last_bids)
db.change_cc_trustee_balance(e.first, (int64_t)e.second, -(int64_t)e.second);
break;
}
default:
MERROR("Invalid auction type");
return false;

View File

@ -0,0 +1,83 @@
// Copyright (c) 2019, 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 "blockchain_db/blockchain_db.h"
#include "cc_command_handler_withdraw_trustee_balance.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "verify"
using namespace cryptonote;
namespace cc
{
cc_command_handler_withdraw_trustee_balance cc_command_handler_withdraw_trustee_balance::instance;
void cc_command_handler_withdraw_trustee_balance::get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const
{
const cc_command_withdraw_trustee_balance_t &withdraw_trustee_balance = boost::get<cc_command_withdraw_trustee_balance_t>(cmd);
cc_in = withdraw_trustee_balance.amount;
cc_out = 0;
}
uint64_t cc_command_handler_withdraw_trustee_balance::get_cost(const cryptonote::cc_command_t &cmd) const
{
return 0;
}
bool cc_command_handler_withdraw_trustee_balance::check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, cryptonote::tx_verification_context &tvc) const
{
const cc_command_withdraw_trustee_balance_t &withdraw_trustee_balance = boost::get<cc_command_withdraw_trustee_balance_t>(cmd);
const uint64_t balance = db.get_cc_trustee_balance(withdraw_trustee_balance.pkey).second;
CHECK_COMMAND_SET(balance > 0, tvc, m_cc_balance, "No balance to withdraw");
CHECK_COMMAND_SET(withdraw_trustee_balance.amount <= balance, tvc, m_cc_balance, "Cannot withdraw more than balance");
return true;
}
bool cc_command_handler_withdraw_trustee_balance::execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, uint64_t tx_fee, game_events_t &events) const
{
const cc_command_withdraw_trustee_balance_t &withdraw_trustee_balance = boost::get<cc_command_withdraw_trustee_balance_t>(cmd);
db.change_cc_trustee_balance(withdraw_trustee_balance.pkey, 0, -(int64_t)withdraw_trustee_balance.amount);
return true;
}
bool cc_command_handler_withdraw_trustee_balance::revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version) const
{
const cc_command_withdraw_trustee_balance_t &withdraw_trustee_balance = boost::get<cc_command_withdraw_trustee_balance_t>(cmd);
db.change_cc_trustee_balance(withdraw_trustee_balance.pkey, 0, (int64_t)withdraw_trustee_balance.amount);
return true;
}
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2019, 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.
#pragma once
#include "cc_command_handler.h"
namespace cc
{
class cc_command_handler_withdraw_trustee_balance: public cc_command_handler
{
public:
virtual void get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const;
virtual uint64_t get_cost(const cryptonote::cc_command_t &cmd) const;
virtual bool check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, cryptonote::tx_verification_context &tvc) const;
virtual bool execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version, uint64_t tx_fee, game_events_t &events) const;
virtual bool revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint8_t hf_version) const;
static cc_command_handler_withdraw_trustee_balance instance;
};
}

View File

@ -2716,7 +2716,7 @@ place_found:
MERROR("Ending auction has no bids");
return false;
}
const uint64_t price = std::get<1>(auction.bids.back());
const uint64_t price = std::get<2>(auction.bids.back());
const uint32_t winner = std::get<0>(auction.bids.back());
switch (auction.type)
{
@ -2742,13 +2742,23 @@ place_found:
events.add_full(cg, winner, auction.seller, 0, std::move(items), -(int64_t)price, 0) << "Won the auction for " << cryptonote::print_money(price);
break;
}
case cc::auction_t::type_account:
CHECK_AND_ASSERT_THROW_MES(winner == 0, "Winner has an account in account auction");
for (const auto &e: auction.entries)
{
events.add_full(cg, auction.seller, 0, 0, ITEM_NONE, 0, 0, 0) << "Sold account via auction for " << cryptonote::print_money(price) << ", held in trust";
}
break;
default:
MERROR("Invalid auction type");
return false;
}
balance_deltas[auction.seller] += price;
balance_deltas[std::get<0>(auction.bids.back())] -= price;
if (auction.type != cc::auction_t::type_account)
{
balance_deltas[auction.seller] += price;
balance_deltas[std::get<0>(auction.bids.back())] -= price;
}
if (auction.mortgage)
{

View File

@ -52,6 +52,7 @@ const cc_command_basenonce_t *get_cc_command_basenonce(const cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<const cc_command_basenonce_t*>
{
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return &cmd; }
@ -128,6 +129,7 @@ const cc_command_basenonce_t *get_cc_command_basenonce(const cc_command_t &cmd)
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_update_item_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_whisper_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return &cmd; }
};
return boost::apply_visitor(visitor(), cmd);
}
@ -136,6 +138,7 @@ cc_command_basenonce_t *get_cc_command_basenonce(cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<cc_command_basenonce_t*>
{
cc_command_basenonce_t *operator()(cryptonote::cc_command_account_auction_bid_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_add_city_specialization_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_allow_settlers_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_allow_styling_t &cmd) const { return &cmd; }
@ -212,6 +215,7 @@ cc_command_basenonce_t *get_cc_command_basenonce(cc_command_t &cmd)
cc_command_basenonce_t *operator()(cryptonote::cc_command_update_item_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_upgrade_building_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_whisper_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return &cmd; }
};
return boost::apply_visitor(visitor(), cmd);
}
@ -220,6 +224,7 @@ const cc_command_base_t *get_cc_command_base(const cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<const cc_command_base_t*>
{
const cc_command_base_t *operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return NULL; }
const cc_command_base_t *operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return &cmd; }
@ -296,6 +301,7 @@ const cc_command_base_t *get_cc_command_base(const cc_command_t &cmd)
const cc_command_base_t *operator()(const cryptonote::cc_command_update_item_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_whisper_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return NULL; }
};
return boost::apply_visitor(visitor(), cmd);
}
@ -304,6 +310,7 @@ cc_command_base_t *get_cc_command_base(cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<cc_command_base_t*>
{
cc_command_base_t *operator()(cryptonote::cc_command_account_auction_bid_t &cmd) const { return NULL; }
cc_command_base_t *operator()(cryptonote::cc_command_add_city_specialization_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_allow_settlers_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_allow_styling_t &cmd) const { return &cmd; }
@ -380,6 +387,7 @@ cc_command_base_t *get_cc_command_base(cc_command_t &cmd)
cc_command_base_t *operator()(cryptonote::cc_command_update_item_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_upgrade_building_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_whisper_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return NULL; }
};
return boost::apply_visitor(visitor(), cmd);
}
@ -388,6 +396,7 @@ bool is_cc_command_restricted(const cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<bool>
{
bool operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return false; }
@ -464,6 +473,7 @@ bool is_cc_command_restricted(const cc_command_t &cmd)
bool operator()(const cryptonote::cc_command_update_item_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_whisper_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return false; }
};
return boost::apply_visitor(visitor(), cmd);
}
@ -472,6 +482,7 @@ bool cc_command_has_signature(const cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<bool>
{
bool operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return true; }
bool operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return true; }
bool operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return true; }
bool operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return true; }
@ -548,6 +559,7 @@ bool cc_command_has_signature(const cc_command_t &cmd)
bool operator()(const cryptonote::cc_command_update_item_t &cmd) const { return true; }
bool operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return true; }
bool operator()(const cryptonote::cc_command_whisper_t &cmd) const { return true; }
bool operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return true; }
};
return boost::apply_visitor(visitor(), cmd);
}
@ -556,6 +568,7 @@ bool cc_command_is_synthesized(const cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<bool>
{
bool operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return false; }
@ -632,6 +645,7 @@ bool cc_command_is_synthesized(const cc_command_t &cmd)
bool operator()(const cryptonote::cc_command_update_item_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_whisper_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return false; }
};
return boost::apply_visitor(visitor(), cmd);
}

View File

@ -1158,6 +1158,7 @@ namespace cryptonote
uint32_t type;
std::vector<entry_t> entries;
uint32_t base_ticks;
uint64_t reserve_price;
std::string title;
std::string description;
@ -1166,6 +1167,7 @@ namespace cryptonote
VARINT_FIELD(type)
FIELD(entries)
VARINT_FIELD(base_ticks)
VARINT_FIELD(reserve_price)
FIELD(title)
FIELD(description)
END_SERIALIZE()
@ -1651,6 +1653,46 @@ namespace cryptonote
END_SERIALIZE()
};
struct cc_command_withdraw_trustee_balance_t: public cc_command_basenonce_t
{
crypto::public_key pkey;
uint64_t amount;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<cc_command_basenonce_t*>(this))
FIELD(pkey)
VARINT_FIELD(amount)
END_SERIALIZE()
};
struct cc_command_account_auction_bid_t: public cc_command_basenonce_t
{
crypto::public_key pkey;
uint32_t auction;
uint64_t price_increase;
bool pm_keys;
crypto::public_key pmspk;
crypto::public_key pmvpk;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<cc_command_basenonce_t*>(this))
FIELD(pkey)
VARINT_FIELD(auction)
VARINT_FIELD(price_increase)
FIELD(pm_keys)
if (pm_keys)
{
FIELD(pmspk)
FIELD(pmvpk)
}
else
{
pmspk = crypto::null_pkey;
pmvpk = crypto::null_pkey;
}
END_SERIALIZE()
};
struct cc_command_game_update_t: public cc_command_basenonce_t
{
struct flag_t
@ -2072,7 +2114,9 @@ namespace cryptonote
cc_command_coru_create_tournament_t,
cc_command_coru_enter_tournament_t,
cc_command_coru_update_tournament_t,
cc_command_coru_jeopardy_pick_t
cc_command_coru_jeopardy_pick_t,
cc_command_withdraw_trustee_balance_t,
cc_command_account_auction_bid_t
> cc_command_t;
cc_command_basenonce_t *get_cc_command_basenonce(cc_command_t &cmd);
@ -2265,6 +2309,8 @@ CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_coru_create_tournament_t,
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_coru_enter_tournament_t, (uint8_t)0x49);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_coru_update_tournament_t, (uint8_t)0x4a);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_coru_jeopardy_pick_t, (uint8_t)0x4b);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_withdraw_trustee_balance_t, (uint8_t)0x4c);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_account_auction_bid_t, (uint8_t)0x4d);
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_none_t, (const char*)"none");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_create_account_t, (const char*)"create_account");
@ -2342,6 +2388,8 @@ CC_VARIANT_TAG(json_archive, cryptonote::cc_command_coru_create_tournament_t, (c
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_coru_enter_tournament_t, (const char*)"coru_enter_tournament");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_coru_update_tournament_t, (const char*)"coru_update_tournament");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_coru_jeopardy_pick_t, (const char*)"coru_jeopardy_pick");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_withdraw_trustee_balance_t, (const char*)"withdraw_trustee_balance");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_account_auction_bid_t, (const char*)"account_auction_bid");
VARIANT_TAG(debug_archive, cryptonote::cc_command_none_t, "none");
VARIANT_TAG(debug_archive, cryptonote::cc_command_create_account_t, "create_account");
@ -2419,3 +2467,5 @@ VARIANT_TAG(debug_archive, cryptonote::cc_command_coru_create_tournament_t, "cor
VARIANT_TAG(debug_archive, cryptonote::cc_command_coru_enter_tournament_t, "coru_enter_tournament");
VARIANT_TAG(debug_archive, cryptonote::cc_command_coru_update_tournament_t, "coru_update_tournament");
VARIANT_TAG(debug_archive, cryptonote::cc_command_coru_jeopardy_pick_t, "coru_jeopardy_pick");
VARIANT_TAG(debug_archive, cryptonote::cc_command_withdraw_trustee_balance_t, "withdraw_trustee_balance");
VARIANT_TAG(debug_archive, cryptonote::cc_command_account_auction_bid_t, "account_auction_bid");

View File

@ -109,6 +109,7 @@ namespace cryptonote
bool m_cc_invalid_coru_deck;
bool m_cc_invalid_coru_move;
bool m_cc_invalid_coru_tournament;
bool m_cc_keys;
class error_builder_t
{

View File

@ -4037,6 +4037,19 @@ bool Blockchain::check_cc_cmd_signature(const transaction& tx) const
return false;
}
}
else if (tx.cc_cmd.type() == typeid(cryptonote::cc_command_account_auction_bid_t))
{
}
else if (tx.cc_cmd.type() == typeid(cryptonote::cc_command_withdraw_trustee_balance_t))
{
const cryptonote::cc_command_withdraw_trustee_balance_t &withdraw_trustee_balance = boost::get<cryptonote::cc_command_withdraw_trustee_balance_t>(tx.cc_cmd);
const crypto::public_key &public_key = withdraw_trustee_balance.pkey;
if (!crypto::check_signature(tx_prefix_hash_with_tag, public_key, tx.cc_account_signature))
{
MERROR_VER("Transaction withdrawing from trustee has invalid signature: public key " << public_key << ", signature " << tx.cc_account_signature);
return false;
}
}
else if (cc_command_is_synthesized(tx.cc_cmd))
{
}
@ -4183,6 +4196,30 @@ bool Blockchain::check_cc_cmd(const transaction& tx, tx_verification_context &tv
return false;
}
}
else if (tx.cc_cmd.type() == typeid(cryptonote::cc_command_withdraw_trustee_balance_t))
{
const cryptonote::cc_command_withdraw_trustee_balance_t &withdraw_trustee_balance = boost::get<cryptonote::cc_command_withdraw_trustee_balance_t>(tx.cc_cmd);
const crypto::public_key &public_key = withdraw_trustee_balance.pkey;
if (!crypto::check_signature(tx_prefix_hash_with_tag, public_key, tx.cc_account_signature))
{
tvc.error << "Transaction withdrawing from trustee has invalid signature: public key " << public_key << ", signature " << tx.cc_account_signature;
MERROR_VER(tvc.error.string());
return false;
}
// nothing more
const uint8_t hf_version = get_current_hard_fork_version();
cryptonote::tx_verification_context tvc{};
if (!cc::check_cc_command(*m_db, tx.cc_cmd, hf_version, tvc))
return false;
}
else if (tx.cc_cmd.type() == typeid(cryptonote::cc_command_account_auction_bid_t))
{
// nothing more
const uint8_t hf_version = get_current_hard_fork_version();
cryptonote::tx_verification_context tvc{};
if (!cc::check_cc_command(*m_db, tx.cc_cmd, hf_version, tvc))
return false;
}
else if (cc_command_is_synthesized(tx.cc_cmd))
{
const uint8_t hf_version = get_current_hard_fork_version();

View File

@ -1360,7 +1360,7 @@ namespace cryptonote
}
// non bare 2.1 txes can include only create_account and transfer commands
if (tx.cc_cmd.type() != typeid(cc_command_none_t) && tx.cc_cmd.type() != typeid(cc_command_create_account_t) &&tx.cc_cmd.type() != typeid(cc_command_transfer_t))
if (tx.cc_cmd.type() != typeid(cc_command_none_t) && tx.cc_cmd.type() != typeid(cc_command_create_account_t) && tx.cc_cmd.type() != typeid(cc_command_transfer_t) && tx.cc_cmd.type() != typeid(cc_command_account_auction_bid_t) && tx.cc_cmd.type() != typeid(cc_command_withdraw_trustee_balance_t))
{
tvc.error << "Non bare tx with bare-only command, rejected for tx id= " << get_transaction_hash(tx);
MERROR_VER(tvc.error.string());

View File

@ -531,15 +531,25 @@ namespace cryptonote
if (cc_source && !cc_dest)
{
// pure withdrawal
cc_command_transfer_t transfer;
transfer.in_amount = cc_source->amount;
transfer.public_key = crypto::null_pkey;
transfer.out_amount = 0;
tx.cc_cmd = transfer;
if (cc_source->account)
{
cc_command_transfer_t transfer;
transfer.in_amount = cc_source->amount;
transfer.public_key = crypto::null_pkey;
transfer.out_amount = 0;
tx.cc_cmd = transfer;
}
else
{
cc_command_withdraw_trustee_balance_t withdraw;
withdraw.amount = cc_source->amount;
withdraw.pkey = cc_source->pkey;
tx.cc_cmd = withdraw;
}
}
else if (!cc_source && cc_dest)
{
// pure deposit, or action creation
// pure deposit, account creation or account auction bid
if (cc_dest->new_account)
{
cc_command_create_account_t create_account;
@ -552,6 +562,17 @@ namespace cryptonote
create_account.inviting_account = cc_dest->inviting_account;
tx.cc_cmd = create_account;
}
else if (cc_dest->auction)
{
cc_command_account_auction_bid_t bid;
bid.pkey = cc_dest->public_key;
bid.auction = cc_dest->auction;
bid.price_increase = cc_dest->amount;
bid.pm_keys = cc_dest->pmspk != crypto::null_pkey && cc_dest->pmvpk != crypto::null_pkey;
bid.pmspk = cc_dest->pmspk;
bid.pmvpk = cc_dest->pmvpk;
tx.cc_cmd = bid;
}
else
{
cc_command_transfer_t transfer;
@ -571,10 +592,10 @@ namespace cryptonote
tx.cc_cmd = transfer;
}
if (cc_source)
if (cc_source && cc_source->account)
{
cryptonote::cc_command_base_t *base = cryptonote::get_cc_command_base(tx.cc_cmd);
CHECK_AND_ASSERT_MES(base, false, "cc_source is set but no base set");
CHECK_AND_ASSERT_MES(base, false, "cc_source is set with account but command is not a base command");
base->cc_account = cc_source->account;
}

View File

@ -109,12 +109,14 @@ namespace cryptonote
struct cc_account_source
{
uint32_t account;
crypto::public_key pkey;
uint64_t amount;
};
struct cc_account_dest
{
bool new_account;
uint32_t auction;
crypto::public_key public_key;
uint64_t amount;
std::string name;

View File

@ -100,6 +100,7 @@ set(game_sources
ui-accept-invitation.cc
ui-add-city-specialization.cc
ui-add-texture.cc
ui-auction-account.cc
ui-auction-items.cc
ui-auctions.cc
ui-building-settings.cc
@ -246,6 +247,7 @@ set(game_headers
tutorial.h
ui-accept-invitation.h
ui-add-texture.h
ui-auction-account.h
ui-auction-items.h
ui-auctions.h
ui-building-settings.h

View File

@ -159,6 +159,8 @@ void PlayerState::reset()
balance = 0;
wallet_balance = 0;
wallet_unlocked_balance = 0;
trustee_locked_balance = 0;
trustee_unlocked_balance = 0;
reserved_balance = 0;
public_key = "";
name = "";
@ -226,6 +228,12 @@ void PlayerState::update(const std::shared_ptr<GameWallet> &wallet)
wallet_unlocked_balance = 0;
}
if (!wallet->get_cc_trustee_balance(wallet->get_cc_pkey(), trustee_locked_balance, trustee_unlocked_balance))
{
trustee_locked_balance = 0;
trustee_unlocked_balance = 0;
}
if (id != 0)
{
// we want to update the list of active coru games, and also detect when a coru game
@ -532,6 +540,35 @@ void GameState::update(const std::shared_ptr<GameWallet> &wallet, uint64_t top_h
new_textures.clear();
}
bool GameState::process_account_auction_bid(const cryptonote::cc_command_account_auction_bid_t &cmd, const std::shared_ptr<GameWallet> &w)
{
const std::string bidder_pkey = epee::string_tools::pod_to_hex(cmd.pkey);
if (bidder_pkey != playerState.public_key)
{
uint64_t our_bid = 0, their_bid = 0;
std::vector<cc::auction_t> auction;
if (w->get_cc_auctions(std::vector<uint32_t>(1, cmd.auction), auction, true) && auction.size() == 1 && auction[0].id == cmd.auction)
{
for (const auto &e: auction[0].bids)
{
const std::string pkey = epee::string_tools::pod_to_hex(std::get<1>(e));
if (pkey == playerState.public_key)
our_bid = std::get<2>(e);
else if (pkey == bidder_pkey)
their_bid = std::get<2>(e);
}
}
if (our_bid > 0)
{
std::string extra = game_util::print_money(their_bid - our_bid);
const std::string title = ignore_player(auction[0].seller) ? ("auction " + std::to_string(cmd.auction)) : auction[0].title;
std::string msg = "Another bidder outbid you by " + extra + " gold for " + title;
SendGameNotification(true, msg, "images/auction-hammer.png");
}
}
return true;
}
bool GameState::process_add_city_specialization(const cryptonote::cc_command_add_city_specialization_t &cmd, const std::shared_ptr<GameWallet> &w)
{
TRIGGER_TUTORIAL(cmd, "city-specialization");
@ -611,12 +648,12 @@ bool GameState::process_auction_bid(const cryptonote::cc_command_auction_bid_t &
{
for (const auto &e: auction[0].bids)
if (std::get<0>(e) == playerState.id)
price = std::get<1>(e);
price = std::get<2>(e);
}
if (price > 0)
{
std::string extra = game_util::print_money(cmd.price - price);
const std::string title = ignore_player(cmd.cc_account) ? ("auction " + std::to_string(cmd.auction)) : auction[0].title;
const std::string title = ignore_player(auction[0].seller) ? ("auction " + std::to_string(cmd.auction)) : auction[0].title;
std::string msg = get_player_name(cmd.cc_account) + " outbid you by " + extra + " gold for " + title;
SendGameNotification(true, msg, "images/auction-hammer.png");
}
@ -1662,6 +1699,18 @@ bool GameState::process_whisper(const cryptonote::cc_command_whisper_t &cmd, con
return true;
}
bool GameState::process_withdraw_trustee_balance(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd, const std::shared_ptr<GameWallet> &w)
{
TRIGGER_TUTORIAL_IF(cmd.pkey == w->get_cc_pkey(), "withdraw-trustee");
if (cmd.pkey == w->get_cc_pkey())
{
std::string amount = game_util::print_money(cmd.amount);
std::string s = "Withdrawn " + amount + " gold held in trust";
SendGameNotification(true, s, "images/red-packet-squint.png");
}
return true;
}
bool GameState::process_name_place(const cryptonote::cc_command_name_place_t &cmd, const std::shared_ptr<GameWallet> &w)
{
if (cmd.city != cityState.id)
@ -1688,6 +1737,7 @@ bool GameState::process_command(const cryptonote::cc_command_t &cmd, const std::
struct visitor: public boost::static_visitor<bool>
{
visitor(GameState &self, const std::shared_ptr<GameWallet> &w): self(self), w(w) {}
bool operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return self.process_account_auction_bid(cmd, w); }
bool operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return self.process_add_city_specialization(cmd, w); }
bool operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return self.process_allow_settlers(cmd, w); }
bool operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return self.process_allow_styling(cmd, w); }
@ -1764,6 +1814,7 @@ bool GameState::process_command(const cryptonote::cc_command_t &cmd, const std::
bool operator()(const cryptonote::cc_command_update_item_t &cmd) const { return self.process_update_item(cmd, w); }
bool operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return self.process_upgrade_building(cmd, w); }
bool operator()(const cryptonote::cc_command_whisper_t &cmd) const { return self.process_whisper(cmd, w); }
bool operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return self.process_withdraw_trustee_balance(cmd, w); }
private:
GameState &self;
const std::shared_ptr<GameWallet> &w;

View File

@ -165,6 +165,8 @@ struct PlayerState: public Urho3D::Object
uint64_t balance;
uint64_t wallet_balance;
uint64_t wallet_unlocked_balance;
uint64_t trustee_locked_balance;
uint64_t trustee_unlocked_balance;
uint64_t reserved_balance;
std::string public_key;
std::string name;
@ -274,6 +276,7 @@ public:
const std::vector<cryptonote::city_t> &get_cities() const;
private:
bool process_account_auction_bid(const cryptonote::cc_command_account_auction_bid_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_add_city_specialization(const cryptonote::cc_command_add_city_specialization_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_allow_settlers(const cryptonote::cc_command_allow_settlers_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_allow_styling(const cryptonote::cc_command_allow_styling_t &cmd, const std::shared_ptr<GameWallet> &w);
@ -350,6 +353,7 @@ private:
bool process_upgrade_building(const cryptonote::cc_command_upgrade_building_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_update_item(const cryptonote::cc_command_update_item_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_whisper(const cryptonote::cc_command_whisper_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_withdraw_trustee_balance(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd, const std::shared_ptr<GameWallet> &w);
void SendGameNotification(bool important, const Urho3D::String &s, const Urho3D::String &icon = "");
void SendGameNotification(bool important, const std::string &s, const Urho3D::String &icon = "");

View File

@ -110,6 +110,7 @@ std::string get_command_string(const GameState *game, const cryptonote::cc_comma
{
struct visitor: public boost::static_visitor<std::string>
{
std::string operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return "Bidding on account auction"; }
std::string operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return "Adding city specialization to " + game->get_city_name(cmd.city); }
std::string operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return std::string(cmd.allow ? "Allowing" : "Denying") + " " + get_player_name_or_group_size(game, cmd.accounts) + " message styling in " + game->get_city_name(cmd.city); }
std::string operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return std::string(cmd.allow ? "Allowing" : "Denying") + " " + get_player_name_or_group_size(game, cmd.accounts) + " message styling in " + game->get_city_name(cmd.city); }
@ -254,6 +255,7 @@ std::string get_command_string(const GameState *game, const cryptonote::cc_comma
return "Upgrading building " + game->get_item_name(cmd.flag) + " by " + std::to_string(cmd.increase) + "%";
}
std::string operator()(const cryptonote::cc_command_whisper_t &cmd) const { return "Leaving a whisper"; }
std::string operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return "Withdrawing " + game_util::print_money(cmd.amount) + " from balance held in trust"; }
visitor(const GameState *game): game(game) {}

View File

@ -355,7 +355,7 @@ public:
bool generate_new_wallet(const char *wallet_file);
void save();
bool deposit(const GameState *game, uint64_t amount, const std::string &name, const std::string &invitation, uint32_t inviting_account);
bool withdraw(uint64_t amount);
bool withdraw(uint64_t amount, bool trustee);
void requestSnapshot(uint32_t city_id);
uint32_t get_cc_account();
crypto::public_key get_cc_pkey();
@ -451,6 +451,8 @@ public:
const std::vector<std::pair<std::string, cc::coru_deck_t>> &get_cc_coru_decks();
void get_cc_recent_coru_games(std::vector<std::pair<uint32_t, uint64_t>> &ids);
void set_cc_recent_coru_games(const std::vector<std::pair<uint32_t, uint64_t>> &ids);
bool get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances);
bool get_cc_trustee_balance(const crypto::public_key &pkey, uint64_t &locked, uint64_t &unlocked);
std::shared_ptr<tools::wallet2> wallet() { boost::unique_lock<boost::mutex> lock(mutex); return internal_wallet; }
bool is_spectator() const { return spectator; }
@ -1406,7 +1408,7 @@ bool GameWalletInternal::deposit(const GameState *game, uint64_t amount, const s
return true;
}
bool GameWalletInternal::withdraw(uint64_t amount)
bool GameWalletInternal::withdraw(uint64_t amount, bool trustee)
{
std::shared_ptr<tools::wallet2> w = wallet();
boost::unique_lock<boost::mutex> lock(mutex);
@ -1431,7 +1433,8 @@ bool GameWalletInternal::withdraw(uint64_t amount)
new MessageBox(context_, String("Your in-game balance is only ") + game_util::print_money(balance).c_str());
return false;
}
cc_source.account = account_id;
cc_source.account = trustee ? 0 : account_id;
cc_source.pkey = trustee ? w->get_cc_pkey() : crypto::null_pkey;
cc_source.amount = amount;
uint32_t priority = w->adjust_priority(0);
@ -1803,6 +1806,20 @@ void GameWalletInternal::set_cc_recent_coru_games(const std::vector<std::pair<ui
w->set_cc_recent_coru_games(ids);
}
bool GameWalletInternal::get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances)
{
std::shared_ptr<tools::wallet2> w = wallet();
boost::unique_lock<boost::mutex> lock(mutex);
return w->get_cc_trustee_balances(balances);
}
bool GameWalletInternal::get_cc_trustee_balance(const crypto::public_key &pkey, uint64_t &locked, uint64_t &unlocked)
{
std::shared_ptr<tools::wallet2> w = wallet();
boost::unique_lock<boost::mutex> lock(mutex);
return w->get_cc_trustee_balance(pkey, locked, unlocked);
}
bool GameWalletInternal::get_cc_accounts(std::vector<std::tuple<uint32_t, std::string, bool, bool>> &accounts)
{
std::shared_ptr<tools::wallet2> w = wallet();
@ -2757,6 +2774,7 @@ void GameWalletInternal::on_reorg(uint64_t height)
{
struct visitor: public boost::static_visitor<bool>
{
bool operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return false; }
@ -2817,6 +2835,7 @@ void GameWalletInternal::on_reorg(uint64_t height)
bool operator()(const cryptonote::cc_command_repair_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_research_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_resize_flag_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_retrieve_items_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_script_choice_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_service_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_set_merchant_ship_items_t &cmd) const { return false; }
@ -2832,7 +2851,7 @@ void GameWalletInternal::on_reorg(uint64_t height)
bool operator()(const cryptonote::cc_command_update_item_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_whisper_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_retrieve_items_t &cmd) const { return false; }
bool operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return false; }
};
need_snapshot = apply_visitor(visitor(), cmd);
if (need_snapshot)
@ -3019,9 +3038,9 @@ bool GameWallet::deposit(const GameState *game, uint64_t amount, const std::stri
return internal->deposit(game, amount, name, invitation, inviting_account);
}
bool GameWallet::withdraw(uint64_t amount)
bool GameWallet::withdraw(uint64_t amount, bool trustee)
{
return internal->withdraw(amount);
return internal->withdraw(amount, trustee);
}
bool GameWallet::get_cc_order_book(std::vector<cryptonote::matchable_order_as_string_t> *bids, std::vector<cryptonote::matchable_order_as_string_t> *offers, const std::vector<uint32_t> &type, const std::vector<uint32_t> &id)
@ -3285,6 +3304,16 @@ void GameWallet::set_cc_recent_coru_games(const std::vector<std::pair<uint32_t,
internal->set_cc_recent_coru_games(ids);
}
bool GameWallet::get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances)
{
return internal->get_cc_trustee_balances(balances);
}
bool GameWallet::get_cc_trustee_balance(const crypto::public_key &pkey, uint64_t &locked, uint64_t &unlocked)
{
return internal->get_cc_trustee_balance(pkey, locked, unlocked);
}
uint32_t GameWallet::get_cc_account()
{
return internal->get_cc_account();

View File

@ -79,7 +79,7 @@ public:
void load(const char *wallet_file);
void save();
bool deposit(const GameState *game, uint64_t amount, const std::string &name = "", const std::string &invitation = "", uint32_t inviting_account = 0);
bool withdraw(uint64_t amount);
bool withdraw(uint64_t amount, bool trustee);
void requestSnapshot(uint32_t city_id);
uint32_t get_cc_account();
crypto::public_key get_cc_pkey();
@ -168,6 +168,8 @@ public:
const std::vector<std::pair<std::string, cc::coru_deck_t>> &get_cc_coru_decks();
void get_cc_recent_coru_games(std::vector<std::pair<uint32_t, uint64_t>> &ids);
void set_cc_recent_coru_games(const std::vector<std::pair<uint32_t, uint64_t>> &ids);
bool get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances);
bool get_cc_trustee_balance(const crypto::public_key &pkey, uint64_t &locked, uint64_t &unlocked);
const std::vector<cc::cc_message_t> get_cc_messages();
size_t get_num_unread_cc_messages();

View File

@ -524,6 +524,7 @@ public:
void HandleCarveRunestone(StringHash eventType, VariantMap& eventData);
void HandleNewAuctionFlag(StringHash eventType, VariantMap& eventData);
void HandleNewAuctionItem(StringHash eventType, VariantMap& eventData);
void HandleNewAuctionAccount(StringHash eventType, VariantMap& eventData);
void HandleBidOnAuction(StringHash eventType, VariantMap& eventData);
void HandleAllowSettlers(StringHash eventType, VariantMap& eventData);
void HandleAllowStyling(StringHash eventType, VariantMap& eventData);
@ -1760,6 +1761,7 @@ void CryptoCityUrho3D::SetupUI()
SubscribeToEvent(ui, E_CRYPTOCITY_CARVE_RUNESTONE, URHO3D_HANDLER(CryptoCityUrho3D, HandleCarveRunestone));
SubscribeToEvent(ui, E_CRYPTOCITY_NEW_AUCTION_FLAG, URHO3D_HANDLER(CryptoCityUrho3D, HandleNewAuctionFlag));
SubscribeToEvent(ui, E_CRYPTOCITY_NEW_AUCTION_ITEM, URHO3D_HANDLER(CryptoCityUrho3D, HandleNewAuctionItem));
SubscribeToEvent(ui, E_CRYPTOCITY_NEW_AUCTION_ACCOUNT, URHO3D_HANDLER(CryptoCityUrho3D, HandleNewAuctionAccount));
SubscribeToEvent(ui, E_CRYPTOCITY_BID_ON_AUCTION, URHO3D_HANDLER(CryptoCityUrho3D, HandleBidOnAuction));
SubscribeToEvent(ui, E_CRYPTOCITY_ALLOW_SETTLERS, URHO3D_HANDLER(CryptoCityUrho3D, HandleAllowSettlers));
SubscribeToEvent(ui, E_CRYPTOCITY_ALLOW_STYLING, URHO3D_HANDLER(CryptoCityUrho3D, HandleAllowStyling));
@ -4067,7 +4069,8 @@ void CryptoCityUrho3D::HandleWithdraw(StringHash eventType, VariantMap& eventDat
new MessageBox(context_, "Not enough in-game balance, balance is " + game_util::print_money(gameState.playerState.balance));
return;
}
wallet->withdraw(amount);
bool trustee = eventData[Withdraw::P_TRUSTEE].GetBool();
wallet->withdraw(amount, trustee);
}
void CryptoCityUrho3D::HandleBuildingSettings(StringHash eventType, VariantMap& eventData)
@ -5340,6 +5343,7 @@ void CryptoCityUrho3D::HandleNewAuctionFlag(StringHash eventType, VariantMap& ev
for (const uint32_t flag: *flags)
cmd.entries.push_back({flag, 1});
cmd.base_ticks = eventData[NewAuctionFlag::P_BASE_TICKS].GetUInt();
cmd.reserve_price = eventData[NewAuctionFlag::P_RESERVE_PRICE].GetUInt64();
cmd.title = eventData[NewAuctionFlag::P_TITLE].GetString().CString();
cmd.description = eventData[NewAuctionFlag::P_DESCRIPTION].GetString().CString();
@ -5361,12 +5365,33 @@ void CryptoCityUrho3D::HandleNewAuctionItem(StringHash eventType, VariantMap& ev
for (const auto &q: *v)
cmd.entries.push_back({q.first, q.second});
cmd.base_ticks = eventData[NewAuctionItem::P_BASE_TICKS].GetUInt();
cmd.reserve_price = eventData[NewAuctionItem::P_RESERVE_PRICE].GetUInt64();
cmd.title = eventData[NewAuctionItem::P_TITLE].GetString().CString();
cmd.description = eventData[NewAuctionItem::P_DESCRIPTION].GetString().CString();
SendCommand(cmd);
}
void CryptoCityUrho3D::HandleNewAuctionAccount(StringHash eventType, VariantMap& eventData)
{
if (!wallet || !wallet->wallet())
{
new MessageBox(context_, "No wallet loaded - load a wallet to be able to auction account");
return;
}
cryptonote::cc_command_create_auction_t cmd;
cmd.cc_account = wallet->get_cc_account();
cmd.type = cc::auction_t::type_account;
cmd.entries.push_back({cmd.cc_account, 1});
cmd.base_ticks = eventData[NewAuctionAccount::P_BASE_TICKS].GetUInt();
cmd.reserve_price = eventData[NewAuctionAccount::P_RESERVE_PRICE].GetUInt64();
cmd.title = eventData[NewAuctionAccount::P_TITLE].GetString().CString();
cmd.description = eventData[NewAuctionAccount::P_DESCRIPTION].GetString().CString();
SendCommand(cmd);
}
void CryptoCityUrho3D::HandleBidOnAuction(StringHash eventType, VariantMap& eventData)
{
if (!wallet || !wallet->wallet())
@ -9674,9 +9699,9 @@ void CryptoCityUrho3D::NotifyGameUpdate(const cryptonote::block *b)
else
{
uint32_t player_id = std::get<0>(e.bids.back());
std::string price = game_util::print_money(std::get<1>(e.bids.back()));
std::string price = game_util::print_money(std::get<2>(e.bids.back()));
game_util::reduce_amount_zeroes(price);
msg = gameState.get_player_name(player_id, true) + " won the " + e.title + " auction for " + price;
msg = (player_id ? gameState.get_player_name(player_id, true) : std::string("Someone")) + " won the " + e.title + " auction for " + price;
}
if (!msg.empty())
ui->AddToastNotification(msg.c_str(), "images/auction-hammer.png");

View File

@ -0,0 +1,134 @@
#include "Urho3D/Core/Context.h"
#include "Urho3D/Resource/ResourceCache.h"
#include "Urho3D/UI/UI.h"
#include "Urho3D/UI/UIEvents.h"
#include <tb/tb_widgets_common.h>
#include <tb/tb_widgets_reader.h>
#include <tb/tb_editfield.h>
#include <tb/tb_inline_select.h>
#include <tb/tb_toggle_container.h>
#include "ui-tb-message-box.h"
#include "game/game-state.h"
#include "game/game-wallet.h"
#include "game/game-util.h"
#include "UTBRendererBatcher.h"
#include "ui-auction-account.h"
using namespace Urho3D;
using namespace tb;
UIAuctionAccountDialog::UIAuctionAccountDialog(Context *ctx, const GameState *game):
UITBWindow(ctx, "cc/auction-account.tb.txt"),
game(game),
refresh(true)
{
durationWidget = GetWidgetByIDAndType<TBInlineSelect>(TBIDC("duration"));
titleWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("title"));
descriptionWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("description"));
reservePriceWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("reserve-price"));
reservePriceErrorWidget = GetWidgetByIDAndType<TBTextField>(TBIDC("reserve-price-error"));
reservePriceErrorContainer = GetWidgetByIDAndType<TBToggleContainer>(TBIDC("reserve-price-error-container"));
SubscribeToEvent(this, E_TB_WIDGET_EVENT, URHO3D_HANDLER(UIAuctionAccountDialog, HandleTBMessage));
SubscribeToEvent(this, E_TB_WINDOW_CLOSED, URHO3D_HANDLER(UIAuctionAccountDialog, HandleClose));
}
UIAuctionAccountDialog::~UIAuctionAccountDialog()
{
}
void UIAuctionAccountDialog::RegisterObject(Context* context)
{
context->RegisterFactory<UIAuctionAccountDialog>();
}
void UIAuctionAccountDialog::Update(const std::shared_ptr<GameWallet> &w)
{
if (refresh)
{
refresh = false;
}
}
void UIAuctionAccountDialog::HandleReservePriceChanged(StringHash eventType, VariantMap& eventData)
{
uint64_t reserve_price = 0;
const TBStr str = reservePriceWidget->GetText();
const bool reserve_price_valid = str.IsEmpty() || cryptonote::parse_amount(reserve_price, str.CStr());
if (!reserve_price_valid)
reservePriceErrorWidget->SetText("Invalid price");
reservePriceErrorContainer->SetValue(!reserve_price_valid);
}
void UIAuctionAccountDialog::HandleOK(StringHash eventType, VariantMap& eventData)
{
uint64_t reserve_price = 0;
const TBStr str = reservePriceWidget->GetText();
if (!str.IsEmpty() && !cryptonote::parse_amount(reserve_price, str.CStr()))
return;
const uint32_t base_ticks = durationWidget->GetValue() * 86400 / DIFFICULTY_TARGET_V2 / GAME_UPDATE_FREQUENCY;
VariantMap& newEventData = GetEventDataMap();
newEventData[AuctionAccountOkayed::P_BASE_TICKS] = base_ticks;
newEventData[AuctionAccountOkayed::P_RESERVE_PRICE] = (unsigned long long)reserve_price;
newEventData[AuctionAccountOkayed::P_TITLE] = titleWidget->GetText().CStr();
newEventData[AuctionAccountOkayed::P_DESCRIPTION] = descriptionWidget->GetText().CStr();
SendEvent(E_AUCTION_ACCOUNT_OKAYED, newEventData);
Close();
}
void UIAuctionAccountDialog::HandleHelp(StringHash eventType, VariantMap& eventData)
{
auto *d = new MessageBox(context_,
"Auctions are set for a set time, chosen by the auction starter.\n"
"\n"
"However, if after the auction reaches that time, there are no bids,\n"
"the auction end will be pushed to the next game tick until there is\n"
"at least one bid.\n"
"\n"
"Moreover, if the last bid on an auction was made after the last game\n"
"tick, the auction end will be pushed to the next tick, to avoid a\n"
"player \"sniping\" an auction.\n",
"Info"
);
d->ResizeToFitContent();
d->SetRect(d->GetRect().CenterIn(UTBRendererBatcher::Singleton().Root().GetRect()));
}
void UIAuctionAccountDialog::HandleTBMessage(StringHash eventType, VariantMap& eventData)
{
#define CONNECT(name, function) do { if (ev->target->GetID() == TBIDC(name)) function(eventType, eventData); } while(0)
using namespace TBWidgetEventNamespace;
TBWidgetEvent *ev = (TBWidgetEvent*)eventData[P_WIDGET_EVENT].GetVoidPtr();
if (ev->type == EVENT_TYPE_CLICK)
{
CONNECT("ok", HandleOK);
CONNECT("cancel", HandleCancel);
CONNECT("help", HandleHelp);
}
else if (ev->type == EVENT_TYPE_CHANGED)
{
CONNECT("reserve-price", HandleReservePriceChanged);
}
#undef CONNECT
}
void UIAuctionAccountDialog::HandleClose(StringHash eventType, VariantMap& eventData)
{
VariantMap& newEventData = GetEventDataMap();
SendEvent(E_AUCTION_ACCOUNT_CLOSED, newEventData);
// Self destruct
Close();
}
void UIAuctionAccountDialog::HandleCancel(StringHash eventType, VariantMap& eventData)
{
VariantMap& newEventData = GetEventDataMap();
SendEvent(E_AUCTION_ACCOUNT_CLOSED, newEventData);
// Self destruct
Close();
}

View File

@ -0,0 +1,59 @@
#ifndef UI_AUCTION_ACCOUNT_H
#define UI_AUCTION_ACCOUNT_H
#include <Urho3D/Core/Object.h>
#include <Urho3D/Container/Str.h>
#include <Urho3D/Container/Ptr.h>
#include <Urho3D/Math/StringHash.h>
#include "ui-tb-window.h"
namespace Urho3D
{
class Context;
}
namespace tb
{
class TBTextField;
class TBEditField;
class TBButton;
class TBInlineSelect;
class TBToggleContainer;
}
class GameState;
class GameWallet;
URHO3D_EVENT(E_AUCTION_ACCOUNT_OKAYED, AuctionAccountOkayed) { URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_RESERVE_PRICE, ReservePrice); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_AUCTION_ACCOUNT_CLOSED, AuctionAccountClosed) {}
class UIAuctionAccountDialog: public UITBWindow
{
public:
UIAuctionAccountDialog(Urho3D::Context *ctx, const GameState *game = NULL);
virtual ~UIAuctionAccountDialog() override;
static void RegisterObject(Urho3D::Context* context);
void Update(const std::shared_ptr<GameWallet> &w);
private:
void HandleOK(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleCancel(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleTBMessage(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleClose(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleReservePriceChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleHelp(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
private:
const GameState *game;
tb::TBInlineSelect *durationWidget;
tb::TBEditField *reservePriceWidget;
tb::TBEditField *titleWidget;
tb::TBEditField *descriptionWidget;
tb::TBToggleContainer *reservePriceErrorContainer;
tb::TBTextField *reservePriceErrorWidget;
bool refresh;
};
#endif

View File

@ -9,6 +9,7 @@
#include <tb/tb_select.h>
#include <tb/tb_editfield.h>
#include <tb/tb_inline_select.h>
#include <tb/tb_toggle_container.h>
#include <tb/tb_font_desc.h>
#include <tb/tb_font_renderer.h>
#include "ui-tb-message-box.h"
@ -76,6 +77,9 @@ UIAuctionItemsDialog::UIAuctionItemsDialog(Context *ctx, const GameState *game):
durationWidget = GetWidgetByIDAndType<TBInlineSelect>(TBIDC("duration"));
titleWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("title"));
descriptionWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("description"));
reservePriceWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("reserve-price"));
reservePriceErrorWidget = GetWidgetByIDAndType<TBTextField>(TBIDC("reserve-price-error"));
reservePriceErrorContainer = GetWidgetByIDAndType<TBToggleContainer>(TBIDC("reserve-price-error-container"));
itemsList->SetSource(&selectableItemSource);
@ -135,9 +139,20 @@ void UIAuctionItemsDialog::FillItemList(const std::shared_ptr<GameWallet> &w)
}
}
void UIAuctionItemsDialog::HandleReservePriceChanged(StringHash eventType, VariantMap& eventData)
{
uint64_t reserve_price = 0;
const TBStr str = reservePriceWidget->GetText();
const bool reserve_price_valid = str.IsEmpty() || cryptonote::parse_amount(reserve_price, str.CStr());
if (!reserve_price_valid)
reservePriceErrorWidget->SetText("Invalid price");
reservePriceErrorContainer->SetValue(!reserve_price_valid);
}
void UIAuctionItemsDialog::HandleOK(StringHash eventType, VariantMap& eventData)
{
std::vector<std::pair<uint32_t, uint32_t>> quantities;
uint64_t reserve_price = 0;
const int n_items = selectableItemSource.GetNumItems();
for (int i = 0; i < n_items; ++i)
@ -165,6 +180,10 @@ void UIAuctionItemsDialog::HandleOK(StringHash eventType, VariantMap& eventData)
continue;
const uint32_t type = selectableItemSource.GetItem(i)->item;
quantities.push_back(std::make_pair(type, amount));
const TBStr str = reservePriceWidget->GetText();
if (!str.IsEmpty() && !cryptonote::parse_amount(reserve_price, str.CStr()))
return;
}
const uint32_t base_ticks = durationWidget->GetValue() * 86400 / DIFFICULTY_TARGET_V2 / GAME_UPDATE_FREQUENCY;
@ -172,6 +191,7 @@ void UIAuctionItemsDialog::HandleOK(StringHash eventType, VariantMap& eventData)
VariantMap& newEventData = GetEventDataMap();
newEventData[AuctionItemsOkayed::P_QUANTITIES] = &quantities;
newEventData[AuctionItemsOkayed::P_BASE_TICKS] = base_ticks;
newEventData[AuctionItemsOkayed::P_RESERVE_PRICE] = (unsigned long long)reserve_price;
newEventData[AuctionItemsOkayed::P_TITLE] = titleWidget->GetText().CStr();
newEventData[AuctionItemsOkayed::P_DESCRIPTION] = descriptionWidget->GetText().CStr();
SendEvent(E_AUCTION_ITEMS_OKAYED, newEventData);
@ -213,6 +233,7 @@ void UIAuctionItemsDialog::HandleTBMessage(StringHash eventType, VariantMap& eve
{
CONNECT("search", HandleFilterChanged);
CONNECT("amount", HandleAmountChanged);
CONNECT("reserve-price", HandleReservePriceChanged);
}
#undef CONNECT
}

View File

@ -21,12 +21,13 @@ namespace tb
class TBEditField;
class TBButton;
class TBInlineSelect;
class TBToggleContainer;
}
class GameState;
class GameWallet;
URHO3D_EVENT(E_AUCTION_ITEMS_OKAYED, AuctionItemsOkayed) { URHO3D_PARAM(P_QUANTITIES, Quantities); URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_AUCTION_ITEMS_OKAYED, AuctionItemsOkayed) { URHO3D_PARAM(P_QUANTITIES, Quantities); URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_RESERVE_PRICE, ReservePrice); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_AUCTION_ITEMS_CLOSED, AuctionItemsClosed) {}
class UIAuctionItemsDialog: public UITBWindow
@ -46,6 +47,7 @@ private:
void HandleClose(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleFilterChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleAmountChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleReservePriceChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleHelp(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void FillItemList(const std::shared_ptr<GameWallet> &w);
@ -89,8 +91,11 @@ private:
tb::TBSelectList *itemsList;
tb::TBEditField *searchWidget;
tb::TBInlineSelect *durationWidget;
tb::TBEditField *reservePriceWidget;
tb::TBEditField *titleWidget;
tb::TBEditField *descriptionWidget;
tb::TBToggleContainer *reservePriceErrorContainer;
tb::TBTextField *reservePriceErrorWidget;
bool refresh;
};

View File

@ -49,8 +49,13 @@ UIAuctionsDialog::AuctionWidget::AuctionWidget(UIAuctionsDialog::AuctionItem *it
deadline->SetText(tools::get_human_readable_timespan(blocks_left * DIFFICULTY_TARGET_V2));
deadline->SetIgnoreInput(true);
TBToggleContainer *reserve_price_container = GetWidgetByIDAndType<TBToggleContainer>(TBIDC("reserve-price-container"));
reserve_price_container->SetValue(item->auction.reserve_price > 0);
TBTextField *reserve_price = GetWidgetByIDAndType<TBTextField>(TBIDC("reserve-price"));
reserve_price->SetText(game_util::print_money(item->auction.reserve_price).c_str());
TBImageWidget *icon = GetWidgetByIDAndType<TBImageWidget>(TBIDC("icon"));
const bool has_bid = std::find_if(item->auction.bids.begin(), item->auction.bids.end(), [item](const std::tuple<uint32_t, uint64_t, uint64_t> &bid) {
const bool has_bid = std::find_if(item->auction.bids.begin(), item->auction.bids.end(), [item](const std::tuple<uint32_t, crypto::public_key, uint64_t, uint64_t> &bid) {
return std::get<0>(bid) == item->dialog->game->playerState.id;
}) != item->auction.bids.end();
const bool has_best_bid = !item->auction.bids.empty() && std::get<0>(item->auction.bids.back()) == item->dialog->game->playerState.id;
@ -105,6 +110,11 @@ std::string UIAuctionsDialog::AuctionItem::get_item_string(const GameState *game
return std::to_string(a.entries[0].second) + " " + game->get_item_name(a.entries[0].first);
else
return "A set of items of " + std::to_string(a.entries.size()) + " different types";
case cc::auction_t::type_account:
if (a.entries.size() == 1)
return "The '" + game->get_player_name(a.entries[0].first) + "' Townforge account";
else
return "Error: more than one account in auction";
default:
return "Unsupported type";
}
@ -188,6 +198,12 @@ std::string UIAuctionsDialog::GetAuctionDetails(const std::shared_ptr<GameWallet
}
}
break;
case cc::auction_t::type_account:
for (const auto &e: auction.entries)
{
ss << "The '" + game->get_player_name(e.first) + "' Townforge account\n";
}
break;
default:
ss << "Unknown type";
break;
@ -235,7 +251,7 @@ void UIAuctionsDialog::UpdateDescriptions(const std::shared_ptr<GameWallet> &w)
const AuctionItem *item = auctionSource.GetItem(sel);
if (item)
{
const uint64_t bid_price = item->auction.bids.empty() ? 0 : std::get<1>(item->auction.bids.back());
const uint64_t bid_price = item->auction.bids.empty() ? 0 : std::get<2>(item->auction.bids.back());
const uint32_t bid_account = item->auction.bids.empty() ? 0 : std::get<0>(item->auction.bids.back());
std::string s = game_util::print_money(bid_price).c_str();
if (bid_account)

View File

@ -87,6 +87,9 @@ UINewAuctionDialog::UINewAuctionDialog(Context *ctx):
titleErrorContainer = GetWidgetByIDAndType<TBToggleContainer>(TBIDC("title-error-container"));
descErrorWidget = GetWidgetByIDAndType<TBTextField>(TBIDC("desc-error"));
descErrorContainer = GetWidgetByIDAndType<TBToggleContainer>(TBIDC("desc-error-container"));
reservePriceWidget = GetWidgetByIDAndType<TBEditField>(TBIDC("reserve-price"));
reservePriceErrorWidget = GetWidgetByIDAndType<TBTextField>(TBIDC("reserve-price-error"));
reservePriceErrorContainer = GetWidgetByIDAndType<TBToggleContainer>(TBIDC("reserve-price-error-container"));
flagList->SetSource(&flag_source);
@ -131,6 +134,16 @@ void UINewAuctionDialog::Update(const GameState *game, const std::shared_ptr<Gam
okButton->SetState(WIDGET_STATE_DISABLED, !ok);
}
void UINewAuctionDialog::HandleReservePriceChanged(StringHash eventType, VariantMap& eventData)
{
uint64_t reserve_price = 0;
const TBStr str = reservePriceWidget->GetText();
const bool reserve_price_valid = str.IsEmpty() || cryptonote::parse_amount(reserve_price, str.CStr());
if (!reserve_price_valid)
reservePriceErrorWidget->SetText("Invalid price");
reservePriceErrorContainer->SetValue(!reserve_price_valid);
}
void UINewAuctionDialog::HandleCancel(StringHash eventType, VariantMap& eventData)
{
VariantMap& newEventData = GetEventDataMap();
@ -158,10 +171,19 @@ void UINewAuctionDialog::HandleOK(StringHash eventType, VariantMap& eventData)
return;
}
uint64_t reserve_price = 0;
const TBStr str = reservePriceWidget->GetText();
if (!str.IsEmpty() && !cryptonote::parse_amount(reserve_price, str.CStr()))
{
new MessageBox(context_, "Invalid reserve price");
return;
}
const uint32_t base_ticks = durationWidget->GetValue() * 86400 / DIFFICULTY_TARGET_V2 / GAME_UPDATE_FREQUENCY;
newEventData[NewAuctionOkayed::P_FLAGS] = &flags;
newEventData[NewAuctionOkayed::P_BASE_TICKS] = base_ticks;
newEventData[NewAuctionOkayed::P_RESERVE_PRICE] = (unsigned long long)reserve_price;
newEventData[NewAuctionOkayed::P_TITLE] = titleWidget->GetText().CStr();
newEventData[NewAuctionOkayed::P_DESCRIPTION] = descriptionWidget->GetText().CStr();
SendEvent(E_NEW_AUCTION_OKAYED, newEventData);
@ -209,6 +231,7 @@ void UINewAuctionDialog::HandleTBMessage(StringHash eventType, VariantMap& event
{
CONNECT("title", HandleTitleChanged);
CONNECT("description", HandleDescriptionChanged);
CONNECT("reserve-price", HandleReservePriceChanged);
}
#undef CONNECT

View File

@ -26,7 +26,7 @@ class Map;
class GameState;
class GameWallet;
URHO3D_EVENT(E_NEW_AUCTION_OKAYED, NewAuctionOkayed) { URHO3D_PARAM(P_FLAGS, Flags); URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_NEW_AUCTION_OKAYED, NewAuctionOkayed) { URHO3D_PARAM(P_FLAGS, Flags); URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_RESERVE_PRICE, ReservePrice); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_NEW_AUCTION_CANCELLED, NewAuctionCancelled) {}
class UINewAuctionDialog: public UITBWindow
@ -39,6 +39,7 @@ public:
void CancelUI();
private:
void HandleReservePriceChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleTitleChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleDescriptionChanged(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleOK(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
@ -94,6 +95,9 @@ private:
tb::TBTextField *titleErrorWidget;
tb::TBToggleContainer *descErrorContainer;
tb::TBTextField *descErrorWidget;
tb::TBEditField *reservePriceWidget;
tb::TBToggleContainer *reservePriceErrorContainer;
tb::TBTextField *reservePriceErrorWidget;
std::string last_refresh_stop_hash;
bool refresh;

View File

@ -50,6 +50,7 @@
#include "ui-smelt.h"
#include "ui-new-message.h"
#include "ui-change-title.h"
#include "ui-auction-account.h"
#include "ui-tb-message-box.h"
#include "caching-source-builder.h"
#include "coin-icon.h"
@ -161,6 +162,7 @@ static std::string get_extra_command_info(const cryptonote::cc_command_t &cmd)
{
struct visitor: public boost::static_visitor<std::string>
{
std::string operator()(const cryptonote::cc_command_account_auction_bid_t &cmd) const { return ""; }
std::string operator()(const cryptonote::cc_command_add_city_specialization_t &cmd) const { return ""; }
std::string operator()(const cryptonote::cc_command_allow_settlers_t &cmd) const { return ""; }
std::string operator()(const cryptonote::cc_command_allow_styling_t &cmd) const { return ""; }
@ -237,6 +239,7 @@ static std::string get_extra_command_info(const cryptonote::cc_command_t &cmd)
std::string operator()(const cryptonote::cc_command_update_item_t &cmd) const { return ""; }
std::string operator()(const cryptonote::cc_command_upgrade_building_t &cmd) const { return ""; }
std::string operator()(const cryptonote::cc_command_whisper_t &cmd) const { return "message: " + cmd.message + "\n"; }
std::string operator()(const cryptonote::cc_command_withdraw_trustee_balance_t &cmd) const { return ""; }
visitor() {}
};
@ -1603,6 +1606,9 @@ UIPlayerInfoDialog::UIPlayerInfoDialog(Context *ctx, const GameState *game, uint
button->SetState(WIDGET_STATE_DISABLED, true);
}
const bool can_auction = game->playerState.has_wallet && game->playerState.id == player_id;
GetWidgetByIDAndType<TBButton>(TBIDC("auction-account"))->SetState(WIDGET_STATE_DISABLED, !can_auction);
const bool can_edit = game->playerState.has_wallet && game->playerState.id == player_id;
playerProfileWidget->SetReadOnly(!can_edit);
savePlayerProfileWidget->SetVisibility(can_edit ? WIDGET_VISIBILITY_VISIBLE : WIDGET_VISIBILITY_INVISIBLE);
@ -2673,6 +2679,8 @@ void UIPlayerInfoDialog::Update(const std::shared_ptr<GameWallet> &w)
const uint32_t max_points = cc::get_attribute_points_for_level(cc::get_badge_score(game->playerState.badges).second);
const bool is_self = game->playerState.has_wallet && game->playerState.id == player_id;
levelUpWidget->SetVisibility(is_self && points < max_points ? WIDGET_VISIBILITY_VISIBLE : WIDGET_VISIBILITY_INVISIBLE);
const bool can_auction = game->playerState.has_wallet && game->playerState.id == player_id;
GetWidgetByIDAndType<TBButton>(TBIDC("auction-account"))->SetState(WIDGET_STATE_DISABLED, !can_auction);
const bool can_edit = game->playerState.has_wallet && game->playerState.id == player_id;
playerProfileWidget->SetReadOnly(!can_edit);
if (level >= MIN_LEVEL_EDIT_PROFILE)
@ -2968,6 +2976,14 @@ void UIPlayerInfoDialog::HandleSelectAccount(StringHash eventType, VariantMap& e
SelectAccount();
}
void UIPlayerInfoDialog::HandleAuctionAccount(StringHash eventType, VariantMap& eventData)
{
UIAuctionAccountDialog *d = new UIAuctionAccountDialog(context_);
SubscribeToEvent(d, E_AUCTION_ACCOUNT_OKAYED, [this](StringHash eventType, VariantMap& eventData) {
SendEvent(E_CRYPTOCITY_NEW_AUCTION_ACCOUNT, eventData);
});
}
void UIPlayerInfoDialog::HandleRepairAll(StringHash eventType, VariantMap& eventData)
{
std::map<uint32_t, uint32_t> total_costs;
@ -3416,6 +3432,7 @@ void UIPlayerInfoDialog::HandleTBMessage(StringHash eventType, VariantMap& event
CONNECT("level-up", HandleLevelUp);
CONNECT("save-player-profile", HandleSavePlayerProfile);
CONNECT("select-account", HandleSelectAccount);
CONNECT("auction-account", HandleAuctionAccount);
CONNECT("repair-all", HandleRepairAll);
CONNECT("history-navigation", HandleHistoryNavigation);
CONNECT("history-go-to-page", HandleHistoryGoToPage);

View File

@ -88,6 +88,7 @@ private:
void HandleLevelUp(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleSavePlayerProfile(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleSelectAccount(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleAuctionAccount(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleRepairAll(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleHistoryNavigation(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleHistoryGoToPage(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);

View File

@ -330,6 +330,8 @@ UIUrho3D::UIUrho3D(Context *ctx, const GameState *gameState):
playerInfoButton = command_window->GetWidgetByIDAndType<TBButton>("player-info");
playerBalanceText = command_window->GetWidgetByIDAndType<TBTextField>("player-game-balance");
playerWalletBalanceText = command_window->GetWidgetByIDAndType<TBTextField>("player-wallet-balance");
balanceHeldInTrustText = command_window->GetWidgetByIDAndType<TBTextField>("balance-held-in-trust");
balanceHeldInTrustContainer = command_window->GetWidgetByIDAndType<TBToggleContainer>("balance-held-in-trust-container");
depositButton = command_window->GetWidgetByIDAndType<TBButton>("player-deposit");
withdrawButton = command_window->GetWidgetByIDAndType<TBButton>("player-withdraw");
loadWalletButton = command_window->GetWidgetByIDAndType<TBButton>("player-load-wallet");
@ -1682,6 +1684,9 @@ void UIUrho3D::UpdatePlayer()
playerWalletBalanceText->SetText(player->has_wallet ? game_util::print_money(player->wallet_balance).c_str() : "<no wallet connected>");
depositButton->SetText(player->id == 0 ? "Create account" : "Deposit");
balanceHeldInTrustContainer->SetValue(player->trustee_unlocked_balance > 0 ? 1 : 0);
balanceHeldInTrustText->SetText(game_util::print_money(player->trustee_unlocked_balance));
if (player->has_wallet)
{
if (player->item_balances != currentPlayerBudget)
@ -1775,10 +1780,19 @@ void UIUrho3D::HandleDeposit(StringHash eventType, VariantMap& eventData)
SendEvent(E_CRYPTOCITY_DEPOSIT, newEventData);
}
void UIUrho3D::HandleWithdraw(StringHash eventType, VariantMap& eventData)
void UIUrho3D::HandleWithdrawAccount(StringHash eventType, VariantMap& eventData)
{
VariantMap newEventData;
newEventData[Withdraw::P_AMOUNT] = eventData[SelectAmount::P_AMOUNT].GetUInt64();
newEventData[Withdraw::P_TRUSTEE] = false;
SendEvent(E_CRYPTOCITY_WITHDRAW, newEventData);
}
void UIUrho3D::HandleWithdrawTrustee(StringHash eventType, VariantMap& eventData)
{
VariantMap newEventData;
newEventData[Withdraw::P_AMOUNT] = eventData[SelectAmount::P_AMOUNT].GetUInt64();
newEventData[Withdraw::P_TRUSTEE] = true;
SendEvent(E_CRYPTOCITY_WITHDRAW, newEventData);
}
@ -1822,7 +1836,7 @@ void UIUrho3D::HandleDepositInfo(StringHash eventType, VariantMap& eventData)
SendTutorialTrigger("screen-deposit");
}
void UIUrho3D::HandleWithdrawInfo(StringHash eventType, VariantMap& eventData)
void UIUrho3D::ShowWithdrawInfo(bool trustee)
{
if (selectAmountDialog)
{
@ -1836,13 +1850,27 @@ void UIUrho3D::HandleWithdrawInfo(StringHash eventType, VariantMap& eventData)
return;
}
std::string message = "Game balance ready to withdraw: " + game_util::print_money(gameState->playerState.balance);
const uint64_t balance = trustee ? gameState->playerState.trustee_unlocked_balance : gameState->playerState.balance;
std::string message = "Game balance ready to withdraw: " + game_util::print_money(balance);
selectAmountDialog = new UISelectAmountDialog(context_, "Enter amount to withdraw", message);
SubscribeToEvent(selectAmountDialog, E_SELECT_AMOUNT, URHO3D_HANDLER(UIUrho3D, HandleWithdraw));
if (trustee)
SubscribeToEvent(selectAmountDialog, E_SELECT_AMOUNT, URHO3D_HANDLER(UIUrho3D, HandleWithdrawTrustee));
else
SubscribeToEvent(selectAmountDialog, E_SELECT_AMOUNT, URHO3D_HANDLER(UIUrho3D, HandleWithdrawAccount));
SubscribeToEvent(selectAmountDialog, E_SELECT_AMOUNT_CLOSED, [this](StringHash, VariantMap&) { selectAmountDialog = NULL; });
SendTutorialTrigger("screen-withdraw");
}
void UIUrho3D::HandleWithdrawInfoAccount(StringHash eventType, VariantMap& eventData)
{
ShowWithdrawInfo(false);
}
void UIUrho3D::HandleWithdrawInfoTrustee(StringHash eventType, VariantMap& eventData)
{
ShowWithdrawInfo(true);
}
void UIUrho3D::HandleBuyLand(StringHash eventType, VariantMap& eventData)
{
VariantMap noEventData;
@ -4201,7 +4229,8 @@ void UIUrho3D::HandleTBMessage(StringHash eventType, VariantMap& eventData)
CONNECT("flag-repair-help", HandleFlagRepairHelp);
CONNECT("player-deposit", HandleDepositInfo);
CONNECT("player-withdraw", HandleWithdrawInfo);
CONNECT("player-withdraw", HandleWithdrawInfoAccount);
CONNECT("player-withdraw-trustee", HandleWithdrawInfoTrustee);
CONNECT("player-load-wallet", HandleLoadWallet);
CONNECT("player-accept-invitation", HandleAcceptInvitation);
CONNECT("player-create-new-wallet", HandleCreateNewWallet);
@ -4595,6 +4624,9 @@ void UIUrho3D::ShowPlayerInfo(uint32_t player_id)
SubscribeToEvent(playerInfoDialog, E_CHANGE_TITLE_OKAYED, [this](StringHash eventType, VariantMap& eventData) {
SendEvent(E_CRYPTOCITY_CHANGE_TITLE, eventData);
});
SubscribeToEvent(playerInfoDialog, E_CRYPTOCITY_NEW_AUCTION_ACCOUNT, [this](StringHash eventType, VariantMap& eventData) {
SendEvent(E_CRYPTOCITY_NEW_AUCTION_ACCOUNT, eventData);
});
if (player_id == 0)
playerInfoDialog->SelectAccount();
SendTutorialTrigger("screen-player-info");

View File

@ -127,7 +127,7 @@ enum EditMode
URHO3D_EVENT(E_CRYPTOCITY_LOAD_WALLET, LoadWallet) {}
URHO3D_EVENT(E_CRYPTOCITY_DEPOSIT, Deposit) { URHO3D_PARAM(P_AMOUNT, Amount); /*, uint64_t */ }
URHO3D_EVENT(E_CRYPTOCITY_CREATE_ACCOUNT, CreateAccount) { URHO3D_PARAM(P_NAME, Name); URHO3D_PARAM(P_AMOUNT, Amount); URHO3D_PARAM(P_INVITATION, Invitation); URHO3D_PARAM(P_INVITING_ACCOUNT, InvitingAccount); }
URHO3D_EVENT(E_CRYPTOCITY_WITHDRAW, Withdraw) { URHO3D_PARAM(P_AMOUNT, Amount); /* uint64_t */ }
URHO3D_EVENT(E_CRYPTOCITY_WITHDRAW, Withdraw) { URHO3D_PARAM(P_AMOUNT, Amount); /* uint64_t */ URHO3D_PARAM(P_TRUSTEE, Trustee); }
URHO3D_EVENT(E_CRYPTOCITY_BUY_LAND, BuyLand) {}
URHO3D_EVENT(E_CRYPTOCITY_BUILDING_SETTINGS, BuildingSettings) { URHO3D_PARAM(P_ROLE, Role); /* uint8_t */ URHO3D_PARAM(P_ECONOMIC_POWER, EconomicPower); /* uint32_t */ URHO3D_PARAM(P_NAME, Name); }
URHO3D_EVENT(E_CRYPTOCITY_UPGRADE_BUILDING, UpgradeBuilding) { URHO3D_PARAM(P_INCREASE, Increase); }
@ -259,8 +259,9 @@ URHO3D_EVENT(E_CRYPTOCITY_SET_TERRAIN_SUBSAMPLING, SetTerrainSubsampling) { URHO
URHO3D_EVENT(E_CRYPTOCITY_NEW_MORTGAGE, NewMortgage) { URHO3D_PARAM(P_NAME, Name); URHO3D_PARAM(P_DESCRIPTION, Description); URHO3D_PARAM(P_ITEM, Item); URHO3D_PARAM(P_TICK_PAYMENT, TickPayment); URHO3D_PARAM(P_MATURITY_PAYMENT, MaturityPayment); URHO3D_PARAM(P_NUM_TICKS_DELAY, NumTicksDelay); URHO3D_PARAM(P_NUM_TICK_PAYMENTS, NumTickPayments); URHO3D_PARAM(P_SHARES, Shares); }
URHO3D_EVENT(E_CRYPTOCITY_CHOP_WOOD, ChopWood) { URHO3D_PARAM(P_QUANTITIES, Quantities); /* vector */ }
URHO3D_EVENT(E_CRYPTOCITY_CARVE_RUNESTONE, CarveRunestone) { URHO3D_PARAM(P_FLAG, Flag); URHO3D_PARAM(P_X, X); URHO3D_PARAM(P_Y, Y); URHO3D_PARAM(P_H, H); URHO3D_PARAM(P_SCRIPT, Script); URHO3D_PARAM(P_OVERRIDES, Overrides); URHO3D_PARAM(P_MESSAGE, Message); }
URHO3D_EVENT(E_CRYPTOCITY_NEW_AUCTION_FLAG, NewAuctionFlag) { URHO3D_PARAM(P_FLAGS, Flags); URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_CRYPTOCITY_NEW_AUCTION_ITEM, NewAuctionItem) { URHO3D_PARAM(P_ITEMS, Items); /* vector */ URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_CRYPTOCITY_NEW_AUCTION_FLAG, NewAuctionFlag) { URHO3D_PARAM(P_FLAGS, Flags); URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_RESERVE_PRICE, ReservePrice); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_CRYPTOCITY_NEW_AUCTION_ITEM, NewAuctionItem) { URHO3D_PARAM(P_ITEMS, Items); /* vector */ URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_RESERVE_PRICE, ReservePrice); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_CRYPTOCITY_NEW_AUCTION_ACCOUNT, NewAuctionAccount) { URHO3D_PARAM(P_BASE_TICKS, BaseTicks); URHO3D_PARAM(P_RESERVE_PRICE, ReservePrice); URHO3D_PARAM(P_TITLE, Title); URHO3D_PARAM(P_DESCRIPTION, Description); }
URHO3D_EVENT(E_CRYPTOCITY_BID_ON_AUCTION, BidOnAuction) { URHO3D_PARAM(P_AUCTION, Auction); URHO3D_PARAM(P_PRICE, Price); }
URHO3D_EVENT(E_CRYPTOCITY_ALLOW_SETTLERS, AllowSettlers) { URHO3D_PARAM(P_ALLOW, Allow); /* vector */ }
URHO3D_EVENT(E_CRYPTOCITY_ALLOW_STYLING, AllowStyling) { URHO3D_PARAM(P_ALLOW, Allow); /* vector */ }
@ -402,9 +403,11 @@ private:
void HandleAcceptInvitation(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleCreateNewWallet(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleDepositInfo(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleWithdrawInfo(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleWithdrawInfoAccount(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleWithdrawInfoTrustee(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleDeposit(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleWithdraw(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleWithdrawAccount(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleWithdrawTrustee(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleBuyLand(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleBuyItems(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleBuy(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
@ -544,6 +547,8 @@ private:
void SetAllSectionsValue(int value);
void ShowWithdrawInfo(bool trustee);
private:
const GameState *gameState;
@ -591,6 +596,8 @@ private:
tb::TBButton *playerInfoButton;
tb::TBTextField *playerBalanceText;
tb::TBTextField *playerWalletBalanceText;
tb::TBToggleContainer *balanceHeldInTrustContainer;
tb::TBTextField *balanceHeldInTrustText;
tb::TBSelectList *playerMaterialList;
tb::TBGenericStringItemSource playerMaterialListSource;
tb::TBToggleContainer *playerAcceptInvitationContainer;

View File

@ -157,7 +157,7 @@ void UIWhatCanIDoDialog::Update(const std::shared_ptr<GameWallet> &w)
if (auction.seller == game->playerState.id)
continue;
++n_auctions;
const auto i = std::find_if(auction.bids.begin(), auction.bids.end(), [this](const std::tuple<uint32_t, uint64_t, uint64_t> &bid){
const auto i = std::find_if(auction.bids.begin(), auction.bids.end(), [this](const std::tuple<uint32_t, crypto::public_key, uint64_t, uint64_t> &bid){
return std::get<0>(bid) == game->playerState.id;
});
const bool has_bid = i != auction.bids.end();

View File

@ -1598,6 +1598,8 @@ namespace cryptonote
add_reason(reason, "Invalid game move");
if ((res.cc_invalid_coru_tournament = tvc.m_cc_invalid_coru_tournament))
add_reason(reason, "Tournament does not exist or is already over");
if ((res.cc_keys = tvc.m_cc_keys))
add_reason(reason, "Keys present when not expected, or missing when expected");
res.cc_error = tvc.error;
@ -6203,20 +6205,22 @@ namespace cryptonote
}
uint32_t bid_account = 0;
std::string bid_pkey;
uint64_t bid_price = 0;
uint64_t bid_height = 0;
if (!auction.bids.empty())
{
const auto &b = auction.bids.back();
bid_account = std::get<0>(b);
bid_price = std::get<1>(b);
bid_height = std::get<2>(b);
bid_pkey = epee::string_tools::pod_to_hex(std::get<1>(b));
bid_price = std::get<2>(b);
bid_height = std::get<3>(b);
}
std::vector<cryptonote::COMMAND_RPC_CC_GET_AUCTIONS::bid_t> bid_history;
if (req.include_bid_history)
{
for (const auto &e: auction.bids)
bid_history.push_back({std::get<0>(e), std::get<1>(e), std::get<2>(e)});
bid_history.push_back({std::get<0>(e), epee::string_tools::pod_to_hex(std::get<1>(e)), std::get<2>(e), std::get<3>(e)});
}
uint64_t projected_end_time;
bool overtime;
@ -6224,7 +6228,10 @@ namespace cryptonote
std::vector<cryptonote::COMMAND_RPC_CC_GET_AUCTIONS::entry_t> entries;
for (const auto &e: auction.entries)
entries.push_back({e.first, e.second});
res.auctions.push_back({auction.id, auction.seller, auction.type, std::move(entries), auction.mortgage, auction.creation_height, auction.base_ticks, auction.title, auction.description, bid_account, bid_price, bid_height, projected_end_time, overtime, std::move(bid_history)});
std::vector<cryptonote::COMMAND_RPC_CC_GET_AUCTIONS::keys_t> keys;
for (const auto &e: auction.keys)
keys.push_back({epee::string_tools::pod_to_hex(e.first), epee::string_tools::pod_to_hex(e.second.first), epee::string_tools::pod_to_hex(e.second.second)});
res.auctions.push_back({auction.id, auction.seller, auction.type, std::move(entries), auction.mortgage, auction.creation_height, auction.base_ticks, auction.reserve_price, auction.title, auction.description, bid_account, std::move(bid_pkey), bid_price, bid_height, projected_end_time, overtime, std::move(bid_history), std::move(keys)});
return true;
});
@ -7398,6 +7405,59 @@ done:
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_cc_get_trustee_balances(const COMMAND_RPC_CC_GET_TRUSTEE_BALANCES::request& req, COMMAND_RPC_CC_GET_TRUSTEE_BALANCES::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
PERF_TIMER(on_cc_get_trustee_balances);
BlockchainDB &db = m_core.get_blockchain_storage().get_db();
try
{
std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> balances;
db.get_cc_trustee_balances(balances);
res.balances.reserve(balances.size());
for (const auto &e: balances)
res.balances.push_back({epee::string_tools::pod_to_hex(e.first), e.second.first, e.second.second});
}
catch (const std::exception &e)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error getting trustee balances";
return false;
}
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_cc_get_trustee_balance(const COMMAND_RPC_CC_GET_TRUSTEE_BALANCE::request& req, COMMAND_RPC_CC_GET_TRUSTEE_BALANCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
PERF_TIMER(on_cc_get_trustee_balance);
BlockchainDB &db = m_core.get_blockchain_storage().get_db();
try
{
crypto::public_key pkey;
if (!epee::string_tools::hex_to_pod(req.pkey, pkey))
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PUBLIC_KEY;
error_resp.message = "Invalid public key";
return false;
}
std::tie(res.locked, res.unlocked) = db.get_cc_trustee_balance(pkey);
}
catch (const std::exception &e)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error getting trustee balance";
return false;
}
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
const command_line::arg_descriptor<std::string, false, true, 2> core_rpc_server::arg_rpc_bind_port = {
"rpc-bind-port"
, "Port for RPC server"

View File

@ -262,6 +262,8 @@ namespace cryptonote
MAP_JON_RPC_WE("cc_get_coru_games", on_cc_get_coru_games, COMMAND_RPC_CC_GET_CORU_GAMES)
MAP_JON_RPC_WE("cc_get_coru_coins_and_runes", on_cc_get_coru_coins_and_runes, COMMAND_RPC_CC_GET_CORU_COINS_AND_RUNES)
MAP_JON_RPC_WE("cc_get_coru_tournaments", on_cc_get_coru_tournaments, COMMAND_RPC_CC_GET_CORU_TOURNAMENTS)
MAP_JON_RPC_WE("cc_get_trustee_balances", on_cc_get_trustee_balances, COMMAND_RPC_CC_GET_TRUSTEE_BALANCES)
MAP_JON_RPC_WE("cc_get_trustee_balance", on_cc_get_trustee_balance, COMMAND_RPC_CC_GET_TRUSTEE_BALANCE)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -413,6 +415,8 @@ namespace cryptonote
bool on_cc_get_coru_games(const COMMAND_RPC_CC_GET_CORU_GAMES::request& req, COMMAND_RPC_CC_GET_CORU_GAMES::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_coru_coins_and_runes(const COMMAND_RPC_CC_GET_CORU_COINS_AND_RUNES::request& req, COMMAND_RPC_CC_GET_CORU_COINS_AND_RUNES::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_coru_tournaments(const COMMAND_RPC_CC_GET_CORU_TOURNAMENTS::request& req, COMMAND_RPC_CC_GET_CORU_TOURNAMENTS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_trustee_balances(const COMMAND_RPC_CC_GET_TRUSTEE_BALANCES::request& req, COMMAND_RPC_CC_GET_TRUSTEE_BALANCES::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_cc_get_trustee_balance(const COMMAND_RPC_CC_GET_TRUSTEE_BALANCE::request& req, COMMAND_RPC_CC_GET_TRUSTEE_BALANCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
//-----------------------
private:

View File

@ -663,6 +663,7 @@ namespace cryptonote
bool cc_invalid_coru_deck;
bool cc_invalid_coru_move;
bool cc_invalid_coru_tournament;
bool cc_keys;
std::string cc_error;
@ -735,6 +736,7 @@ namespace cryptonote
KV_SERIALIZE(cc_invalid_coru_deck)
KV_SERIALIZE(cc_invalid_coru_move)
KV_SERIALIZE(cc_invalid_coru_tournament)
KV_SERIALIZE(cc_keys)
KV_SERIALIZE(cc_error)
@ -5391,16 +5393,31 @@ namespace cryptonote
struct bid_t
{
uint32_t account;
std::string pkey;
uint64_t price;
uint64_t height;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account)
KV_SERIALIZE(pkey)
KV_SERIALIZE(price)
KV_SERIALIZE(height)
END_KV_SERIALIZE_MAP()
};
struct keys_t
{
std::string pkey;
std::string pmspk;
std::string pmvpk;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pkey)
KV_SERIALIZE(pmspk)
KV_SERIALIZE(pmvpk)
END_KV_SERIALIZE_MAP()
};
struct auction_t
{
uint32_t id;
@ -5410,14 +5427,17 @@ namespace cryptonote
uint32_t mortgage;
uint64_t creation_height;
uint32_t base_ticks;
uint64_t reserve_price;
std::string title;
std::string description;
uint32_t bid_account;
std::string bid_pkey;
uint64_t bid_price;
uint64_t bid_height;
uint64_t projected_end_time;
bool overtime;
std::vector<bid_t> bids;
std::vector<keys_t> keys;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id)
@ -5427,14 +5447,17 @@ namespace cryptonote
KV_SERIALIZE(mortgage)
KV_SERIALIZE(creation_height)
KV_SERIALIZE(base_ticks)
KV_SERIALIZE(reserve_price)
KV_SERIALIZE(title)
KV_SERIALIZE(description)
KV_SERIALIZE(bid_account)
KV_SERIALIZE(bid_pkey)
KV_SERIALIZE(bid_price)
KV_SERIALIZE(bid_height)
KV_SERIALIZE(projected_end_time)
KV_SERIALIZE(overtime)
KV_SERIALIZE(bids)
KV_SERIALIZE(keys)
END_KV_SERIALIZE_MAP()
};
@ -6862,4 +6885,69 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_GET_TRUSTEE_BALANCES
{
struct request_t
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct balance_t
{
std::string pkey;
uint64_t locked;
uint64_t unlocked;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pkey)
KV_SERIALIZE(locked)
KV_SERIALIZE(unlocked)
END_KV_SERIALIZE_MAP()
};
struct response_t
{
std::vector<balance_t> balances;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balances)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_GET_TRUSTEE_BALANCE
{
struct request_t
{
std::string pkey;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pkey)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
uint64_t locked;
uint64_t unlocked;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(locked)
KV_SERIALIZE(unlocked)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
}

View File

@ -278,7 +278,7 @@ namespace
const char* USAGE_VERSION("version");
const char* USAGE_CC_DEPOSIT("cc_deposit [index=<N1>[,<N2>,...]] [<priority>] <amount>");
const char* USAGE_CC_WITHDRAW("cc_withdraw <amount>");
const char* USAGE_CC_WITHDRAW("cc_withdraw <amount> [trustee]");
const char* USAGE_CC_TRANSFER("cc_transfer <address> <amount>");
const char* USAGE_CC_BUY_LAND("cc_buy_land <x0> <y0> ( to <x1> <y1> | size <width> <height> ) [<city_id>])");
const char* USAGE_CC_BUILD("cc_build <flag> <dx> <dy> <width> <height> <build_height> <list of blocks>)");
@ -2368,6 +2368,13 @@ bool simple_wallet::cc_withdraw(const std::vector<std::string> &args_)
}
auto local_args = args_;
bool trustee = false;
if (local_args.back() == "trustee")
{
trustee = true;
local_args.pop_back();
}
uint64_t amount;
bool ok = cryptonote::parse_amount(amount, local_args.back());
if (!ok || amount == 0)
@ -2397,7 +2404,8 @@ bool simple_wallet::cc_withdraw(const std::vector<std::string> &args_)
fail_msg_writer() << boost::format(tr("Your in-game balance is only %s")) % cryptonote::print_money(balance);
return true;
}
cc_source.account = account_id;
cc_source.account = trustee ? 0 : account_id;
cc_source.pkey = trustee ? m_wallet->get_cc_pkey() : crypto::null_pkey;
cc_source.amount = amount;
message_writer() << boost::format(tr("Withdrawing %s %s from the Townforge account linked to %s."))
@ -2952,9 +2960,14 @@ bool simple_wallet::cc_status(const std::vector<std::string> &args_)
return true;
}
uint64_t trustee_locked_balance = 0, trustee_unlocked_balance = 0;
m_wallet->get_cc_trustee_balance(m_wallet->get_cc_pkey(), trustee_locked_balance, trustee_unlocked_balance);
const uint32_t id = m_wallet->get_cc_account();
if (id == 0)
{
if (trustee_locked_balance || trustee_unlocked_balance)
message_writer() << tr("Balance held in trust: ") << cryptonote::print_money(trustee_locked_balance) << " locked, " << cryptonote::print_money(trustee_unlocked_balance) << " unlocked";
fail_msg_writer() << tr("You have no in-game account. Use cc_deposit to create one");
return true;
}
@ -2991,6 +3004,8 @@ bool simple_wallet::cc_status(const std::vector<std::string> &args_)
message_writer() << tr("PM keys: ") << pmspk << " " << pmvpk;
message_writer() << tr("Balance: ") << cryptonote::print_money(balance);
if (trustee_locked_balance || trustee_unlocked_balance)
message_writer() << tr("Balance held in trust: ") << cryptonote::print_money(trustee_locked_balance) << " locked, " << cryptonote::print_money(trustee_unlocked_balance) << " unlocked";
std::stringstream ss;
bool first = true;

View File

@ -2194,6 +2194,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback->on_cc_money_received(height, txid, tx, transfer.out_amount, m_cc_balance);
}
}
if (tx.cc_cmd.type() == typeid(cryptonote::cc_command_game_update_t))
{
// in case we acquired or sold an account
lookup_cc_account(m_cc_account, m_cc_balance);
}
}
// Don't try to extract tx public key if tx has no ouputs

View File

@ -1283,6 +1283,8 @@ private:
void remove_cc_coru_deck(const std::string &name);
void replace_cc_coru_deck(const std::string &name, const cc::coru_deck_t &deck);
const std::vector<std::pair<std::string, cc::coru_deck_t>> &get_cc_coru_decks() const { return m_cc_coru_game_decks; }
bool get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances);
bool get_cc_trustee_balance(const crypto::public_key &pkey, uint64_t &locked, uint64_t &unlocked);
void add_cc_vista(const std::string &vista, const std::string &label, const std::string &picture);
void delete_cc_vista(const std::string &vista);

View File

@ -1360,21 +1360,45 @@ bool wallet2::get_cc_auctions(const std::vector<uint32_t> &ids, std::vector<cc::
auctions.reserve(res.auctions.size());
for (auto &e: res.auctions)
{
std::vector<std::tuple<uint32_t, uint64_t, uint64_t>> bids;
std::vector<std::tuple<uint32_t, crypto::public_key, uint64_t, uint64_t>> bids;
if (include_bid_history)
{
for (const auto &f: e.bids)
bids.push_back(std::make_tuple(f.account, f.price, f.height));
{
crypto::public_key pkey;
if (!epee::string_tools::hex_to_pod(f.pkey, pkey))
return false;
bids.push_back(std::make_tuple(f.account, pkey, f.price, f.height));
}
}
else
{
if (e.bid_price > 0)
bids.push_back(std::make_tuple(e.bid_account, e.bid_price, e.bid_height));
{
crypto::public_key bid_pkey;
if (!epee::string_tools::hex_to_pod(e.bid_pkey, bid_pkey))
return false;
bids.push_back(std::make_tuple(e.bid_account, bid_pkey, e.bid_price, e.bid_height));
}
}
std::vector<std::pair<uint32_t, uint32_t>> entries;
for (const auto &entry: e.entries)
{
entries.push_back(std::make_pair(entry.object, entry.amount));
auctions.push_back({e.id, e.seller, e.type, std::move(entries), e.mortgage, e.creation_height, e.base_ticks, std::move(e.title), std::move(e.description), std::move(bids)});
}
std::map<crypto::public_key, std::pair<crypto::public_key, crypto::public_key>> keys;
for (const auto &k: e.keys)
{
crypto::public_key pkey, pmspk, pmvpk;
if (!epee::string_tools::hex_to_pod(k.pkey, pkey))
return false;
if (!epee::string_tools::hex_to_pod(k.pmspk, pmspk))
return false;
if (!epee::string_tools::hex_to_pod(k.pmvpk, pmvpk))
return false;
keys[pkey] = std::make_pair(pmspk, pmvpk);
}
auctions.push_back({e.id, e.seller, e.type, std::move(entries), e.mortgage, e.creation_height, e.base_ticks, e.reserve_price, std::move(e.title), std::move(e.description), std::move(bids), std::move(keys)});
}
return true;
@ -2224,4 +2248,46 @@ void wallet2::replace_cc_coru_deck(const std::string &name, const cc::coru_deck_
add_cc_coru_deck(name, deck);
}
bool wallet2::get_cc_trustee_balances(std::map<crypto::public_key, std::pair<uint64_t, uint64_t>> &balances)
{
cryptonote::COMMAND_RPC_CC_GET_TRUSTEE_BALANCES::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_CC_GET_TRUSTEE_BALANCES::response res;
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json_rpc("/json_rpc", "cc_get_trustee_balances", req, res);
m_daemon_rpc_mutex.unlock();
if (!r || res.status != CORE_RPC_STATUS_OK)
return false;
balances.clear();
for (const auto &e: res.balances)
{
crypto::public_key pkey;
if (!epee::string_tools::hex_to_pod(e.pkey, pkey))
return false;
balances[pkey] = std::make_pair(e.locked, e.unlocked);
}
return true;
}
bool wallet2::get_cc_trustee_balance(const crypto::public_key &pkey, uint64_t &locked, uint64_t &unlocked)
{
cryptonote::COMMAND_RPC_CC_GET_TRUSTEE_BALANCE::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_CC_GET_TRUSTEE_BALANCE::response res;
req.pkey = epee::string_tools::pod_to_hex(pkey);
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json_rpc("/json_rpc", "cc_get_trustee_balance", req, res);
m_daemon_rpc_mutex.unlock();
if (!r || res.status != CORE_RPC_STATUS_OK)
return false;
locked = res.locked;
unlocked = res.unlocked;
return true;
}
}

View File

@ -4244,6 +4244,7 @@ namespace tools
uint32_t priority = m_wallet->adjust_priority(req.priority);
cryptonote::cc_account_dest cc_dest = {
m_wallet->get_cc_account() == 0,
0,
m_wallet->get_cc_pkey(),
req.amount,
req.name,
@ -4297,7 +4298,8 @@ namespace tools
uint64_t mixin = m_wallet->adjust_mixin(0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
cryptonote::cc_account_source cc_source = {
m_wallet->get_cc_account(),
req.trustee ? 0 : m_wallet->get_cc_account(),
req.trustee ? m_wallet->get_cc_pkey() : crypto::null_pkey,
req.amount
};
std::vector<cryptonote::tx_destination_entry> dsts;
@ -4571,14 +4573,8 @@ namespace tools
if (!m_wallet) return not_open(er);
res.account_id = m_wallet->get_cc_account();
if (res.account_id == 0)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "No game account found.";
return false;
}
res.cc_pkey = epee::string_tools::pod_to_hex(m_wallet->get_cc_pkey());
res.cc_balance = m_wallet->get_cc_balance();
res.cc_balance = res.account_id == 0 ? 0 : m_wallet->get_cc_balance();
return true;
}
@ -6675,6 +6671,7 @@ namespace tools
for (const auto &e: req.entries)
cmd.entries.push_back({e.object, e.amount});
cmd.base_ticks = req.base_ticks;
cmd.reserve_price = req.reserve_price;
cmd.title = req.title;
cmd.description = req.description;
@ -8347,6 +8344,62 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_cc_account_auction_bid(const wallet_rpc::COMMAND_RPC_CC_ACCOUNT_AUCTION_BID::request& req, wallet_rpc::COMMAND_RPC_CC_ACCOUNT_AUCTION_BID::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
LOG_PRINT_L3("on_cc_account_auction_bid starts");
if (!m_wallet) return not_open(er);
if (m_restricted)
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
try
{
uint64_t mixin = m_wallet->adjust_mixin(0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
cryptonote::cc_account_dest cc_dest = {
false,
req.auction,
m_wallet->get_cc_pkey(),
req.price_increase + AUCTION_BID_FEE,
"",
0,
crypto::null_pkey,
crypto::null_pkey
};
if (req.first)
m_wallet->get_pm_keys(cc_dest.pmspk, cc_dest.pmvpk);
std::vector<cryptonote::tx_destination_entry> dsts;
cryptonote::tx_destination_entry dst;
cryptonote::account_base dummy;
dummy.generate();
dst.addr = dummy.get_keys().m_account_address;
dst.is_subaddress = false;
dst.is_integrated = false;
dst.amount = 0;
dsts.push_back(dst);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, boost::none, cc_dest, mixin, 0, priority, {}, 0, {});
if (ptx_vector.empty())
{
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
er.message = "No transaction created";
return false;
}
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er);
}
catch (const std::exception& e)
{
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
}
class t_daemon

View File

@ -243,6 +243,7 @@ namespace tools
MAP_JON_RPC_WE("cc_coru_enter_tournament",on_cc_coru_enter_tournament, wallet_rpc::COMMAND_RPC_CC_CORU_ENTER_TOURNAMENT)
MAP_JON_RPC_WE("cc_coru_update_tournament",on_cc_coru_update_tournament, wallet_rpc::COMMAND_RPC_CC_CORU_UPDATE_TOURNAMENT)
MAP_JON_RPC_WE("cc_coru_jeopardy_pick",on_cc_coru_jeopardy_pick, wallet_rpc::COMMAND_RPC_CC_CORU_JEOPARDY_PICK)
MAP_JON_RPC_WE("cc_account_auction_bid",on_cc_account_auction_bid, wallet_rpc::COMMAND_RPC_CC_ACCOUNT_AUCTION_BID)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -416,6 +417,7 @@ namespace tools
bool on_cc_coru_enter_tournament(const wallet_rpc::COMMAND_RPC_CC_CORU_ENTER_TOURNAMENT::request& req, wallet_rpc::COMMAND_RPC_CC_CORU_ENTER_TOURNAMENT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_coru_update_tournament(const wallet_rpc::COMMAND_RPC_CC_CORU_UPDATE_TOURNAMENT::request& req, wallet_rpc::COMMAND_RPC_CC_CORU_UPDATE_TOURNAMENT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_coru_jeopardy_pick(const wallet_rpc::COMMAND_RPC_CC_CORU_JEOPARDY_PICK::request& req, wallet_rpc::COMMAND_RPC_CC_CORU_JEOPARDY_PICK::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_account_auction_bid(const wallet_rpc::COMMAND_RPC_CC_ACCOUNT_AUCTION_BID::request& req, wallet_rpc::COMMAND_RPC_CC_ACCOUNT_AUCTION_BID::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
//json rpc v2
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);

View File

@ -2745,6 +2745,7 @@ namespace wallet_rpc
struct request_t
{
uint64_t amount;
bool trustee;
uint32_t priority;
bool get_tx_keys;
bool do_not_relay;
@ -2753,6 +2754,7 @@ namespace wallet_rpc
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE_OPT(trustee, false)
KV_SERIALIZE(priority)
KV_SERIALIZE(get_tx_keys)
KV_SERIALIZE_OPT(do_not_relay, false)
@ -5411,6 +5413,7 @@ namespace wallet_rpc
uint32_t type;
std::vector<entry_t> entries;
uint32_t base_ticks;
uint64_t reserve_price;
std::string title;
std::string description;
@ -5423,6 +5426,7 @@ namespace wallet_rpc
KV_SERIALIZE(type)
KV_SERIALIZE(entries)
KV_SERIALIZE(base_ticks)
KV_SERIALIZE(reserve_price)
KV_SERIALIZE(title)
KV_SERIALIZE(description)
@ -7275,5 +7279,62 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_ACCOUNT_AUCTION_BID
{
struct request_t
{
uint32_t auction;
uint64_t price_increase;
bool first;
uint32_t priority;
bool get_tx_keys;
bool do_not_relay;
bool get_tx_hex;
bool get_tx_metadata;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(auction)
KV_SERIALIZE(price_increase)
KV_SERIALIZE(first)
KV_SERIALIZE(priority)
KV_SERIALIZE(get_tx_keys)
KV_SERIALIZE_OPT(do_not_relay, false)
KV_SERIALIZE_OPT(get_tx_hex, false)
KV_SERIALIZE_OPT(get_tx_metadata, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::list<std::string> tx_hash_list;
std::list<std::string> tx_key_list;
std::list<uint64_t> amount_list;
std::list<uint64_t> fee_list;
std::list<uint64_t> weight_list;
std::list<std::string> tx_blob_list;
std::list<std::string> tx_metadata_list;
std::string multisig_txset;
std::string unsigned_txset;
std::list<key_image_list> spent_key_images_list;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash_list)
KV_SERIALIZE(tx_key_list)
KV_SERIALIZE(amount_list)
KV_SERIALIZE(fee_list)
KV_SERIALIZE(weight_list)
KV_SERIALIZE(tx_blob_list)
KV_SERIALIZE(tx_metadata_list)
KV_SERIALIZE(multisig_txset)
KV_SERIALIZE(unsigned_txset)
KV_SERIALIZE(spent_key_images_list)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
}
}

View File

@ -472,7 +472,7 @@ bool gen_cc_tx_validation_base::generate_with_full(std::vector<test_event_entry>
const auto &sending_account = src.real_output > 0 && src.real_output <= 8 ? cc_test_accounts[src.real_output - 1] : miner_account;
subaddresses[sending_account.get_keys().m_account_address.m_spend_public_key] = {0,0};
const rct::RCTConfig rct_config = { rct::RangeProofPaddedBulletproof, 0 };
cc_account_dest cc_create_account_dest = {true, cc::get_cc_public_key(sending_account.get_keys().m_spend_secret_key), CRYPTONOTE_CC_NEW_ACCOUNT_FEE + initial_funding[i], "player " + std::to_string(i), 0, get_sample_pmspk(), get_sample_pmvpk()};
cc_account_dest cc_create_account_dest = {true, 0, cc::get_cc_public_key(sending_account.get_keys().m_spend_secret_key), CRYPTONOTE_CC_NEW_ACCOUNT_FEE + initial_funding[i], "player " + std::to_string(i), 0, get_sample_pmspk(), get_sample_pmvpk()};
expected_balance[i] += initial_funding[i];
expected_treasury_balance += CRYPTONOTE_CC_NEW_ACCOUNT_FEE - NEWBIE_COIN_GOLD_CONTENT;
@ -545,7 +545,7 @@ bool gen_cc_tx_validation_base::generate_with_full(std::vector<test_event_entry>
subaddresses[sending_account.get_keys().m_account_address.m_spend_public_key] = {0,0};
const rct::RCTConfig rct_config = { rct::RangeProofPaddedBulletproof, 0 };
const int dest_idx = preparation == prep_large_balance ? 3 : 0;
cc_account_dest cc_account_dest = {false, cc::get_cc_public_key(cc_test_accounts[dest_idx].get_keys().m_spend_secret_key), n_outs_this_time * 17*COIN, {}, 0, get_sample_pmspk(), get_sample_pmvpk()};
cc_account_dest cc_account_dest = {false, 0, cc::get_cc_public_key(cc_test_accounts[dest_idx].get_keys().m_spend_secret_key), n_outs_this_time * 17*COIN, {}, 0, get_sample_pmspk(), get_sample_pmvpk()};
expected_balance[dest_idx] += cc_account_dest.amount;
bool r = construct_tx_and_get_tx_key(sending_account.get_keys(), subaddresses, sources, boost::none, destinations, cc_account_dest, cryptonote::account_public_address{}, std::vector<uint8_t>(), tx, 0, tx_key, additional_tx_keys, true, rct_config, true);
@ -823,6 +823,7 @@ bool gen_cc_tx_valid_create_account::generate(std::vector<test_event_entry>& eve
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[7].get_keys().m_spend_secret_key),
CRYPTONOTE_CC_NEW_ACCOUNT_FEE,
"test name",
@ -850,6 +851,7 @@ bool gen_cc_tx_invalid_create_account_low_fee::generate(std::vector<test_event_e
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[7].get_keys().m_spend_secret_key),
CRYPTONOTE_CC_NEW_ACCOUNT_FEE - 1,
"test name",
@ -871,6 +873,7 @@ bool gen_cc_tx_valid_create_account_including_deposit::generate(std::vector<test
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[7].get_keys().m_spend_secret_key),
CRYPTONOTE_CC_NEW_ACCOUNT_FEE + 42,
"test name",
@ -896,7 +899,7 @@ bool gen_cc_tx_invalid_cc_one_in_no_out_invalid_cc_account::generate(std::vector
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {8, 1};
const cryptonote::cc_account_source source = {8, crypto::null_pkey, 1};
return generate_with(events, source, boost::none, prep_none, 1, mixin, amount_paid, false, {}, false, invalid, NULL, NULL);
}
@ -905,9 +908,10 @@ bool gen_cc_tx_invalid_cc_one_in_one_out_invalid_cc_account::generate(std::vecto
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {8, 1};
const cryptonote::cc_account_source source = {8, crypto::null_pkey, 1};
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[7].get_keys().m_spend_secret_key),
CRYPTONOTE_CC_NEW_ACCOUNT_FEE,
"test name",
@ -945,9 +949,10 @@ bool gen_cc_tx_valid_cc_one_in_one_out::generate(std::vector<test_event_entry>&
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
5000,
"test name",
@ -977,9 +982,10 @@ bool gen_cc_tx_invalid_cc_one_in_one_out_more_than_inputs::generate(std::vector<
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 17*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
1*COIN,
"test name",
@ -999,9 +1005,10 @@ bool gen_cc_tx_valid_cc_one_in_one_out_more_than_rct_inputs_but_balance_is_large
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 15*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 15*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
30*COIN,
"test name",
@ -1033,9 +1040,10 @@ bool gen_cc_tx_invalid_cc_one_in_one_out_more_than_rct_inputs_but_balance_is_not
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 40*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 40*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
50*COIN,
"test name",
@ -1051,9 +1059,10 @@ bool gen_cc_tx_invalid_cc_multiple_txes_spend_more_than_balance::generate(std::v
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 15*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 15*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
5000,
"test name",
@ -1069,9 +1078,10 @@ bool gen_cc_tx_invalid_cc_bad_signature::generate(std::vector<test_event_entry>&
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
5000,
"test name",
@ -1090,9 +1100,10 @@ bool gen_cc_tx_invalid_cc_signature_by_wrong_keys::generate(std::vector<test_eve
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
false,
0,
cc::get_cc_public_key(cc_test_accounts[1].get_keys().m_spend_secret_key),
5000,
"test name",
@ -1112,7 +1123,7 @@ bool gen_cc_tx_valid_cc_one_in_no_out::generate(std::vector<test_event_entry>& e
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 16*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 16*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
return generate_with(events, source, boost::none, prep_create_accounts, 1, mixin, amount_paid, false, {}, false, valid, NULL, NULL);
}
@ -1135,7 +1146,7 @@ bool gen_cc_tx_valid_cc_pop_reverts::generate(std::vector<test_event_entry>& eve
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 1*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 16*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 16*COIN}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
return generate_with(events, source, boost::none, prep_create_accounts, 1, mixin, amount_paid, false, {}, true, valid, NULL, NULL);
}
@ -1158,7 +1169,7 @@ bool gen_cc_tx_invalid_cc_bare_one_in_no_out::generate(std::vector<test_event_en
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 0;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 1}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
return generate_with(events, source, boost::none, prep_create_accounts, 1, mixin, amount_paid, true, {}, false, invalid, NULL, NULL);
}
@ -1169,6 +1180,7 @@ bool gen_cc_tx_invalid_cc_bare_no_in_one_out::generate(std::vector<test_event_en
const uint64_t amount_paid = 0;
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[3].get_keys().m_spend_secret_key),
1,
"test name",
@ -1184,9 +1196,10 @@ bool gen_cc_tx_valid_cc_bare_one_in_one_out::generate(std::vector<test_event_ent
init_cc_test_accounts();
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 0;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, 1234567890}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, 1234567890}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[3].get_keys().m_spend_secret_key),
1234567890,
"test name",
@ -1217,9 +1230,10 @@ bool gen_cc_tx_invalid_cc_bare_transfer_whole_balance_nothing_left_for_fee::gene
const unsigned int mixin = DEFAULT_MIXIN;
const uint64_t amount_paid = 0;
uint64_t balance = 34*COIN;
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, balance}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_source source = {FIRST_TEST_ACCOUNT, crypto::null_pkey, balance}; // FIRST_TEST_ACCOUNT is cc_test_accounts[0]
const cryptonote::cc_account_dest dest = {
true,
0,
cc::get_cc_public_key(cc_test_accounts[3].get_keys().m_spend_secret_key),
balance,
"test name",

View File

@ -425,7 +425,7 @@ bool db_tests_cc_auctions(cryptonote::BlockchainDB &db)
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);
const uint32_t id = db.allocate_cc_auction(1, cc::auction_t::type_flag, {std::make_pair(1, 1)}, 2, 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){
@ -435,6 +435,7 @@ bool db_tests_cc_auctions(cryptonote::BlockchainDB &db)
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());
@ -453,15 +454,15 @@ bool db_tests_cc_auctions(cryptonote::BlockchainDB &db)
DB_TESTS_ASSERT(ad.entries[0].second == 1);
DB_TESTS_ASSERT(ad.bids.empty());
db.add_cc_auction_bid(1, 2, 200, 200);
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, 200, 200));
db.add_cc_auction_bid(1, 3, 400, 300);
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, 200, 200));
DB_TESTS_ASSERT(ad.bids[1] == std::make_tuple(3, 400, 300));
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;
@ -1255,3 +1256,88 @@ bool db_tests_cc_coru_tournaments(cryptonote::BlockchainDB &db)
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;
}

View File

@ -166,6 +166,7 @@ int main(int argc, char* argv[])
RUN(cc_coru_requests);
RUN(cc_coru_games);
RUN(cc_coru_tournaments);
RUN(cc_trustee_balances);
db->batch_stop();

View File

@ -145,12 +145,12 @@ NUM_CUSTOM_ITEM_USER_DATA = 4
CHOP_WOOD_LABOUR_PER_100_WOOD = 5
PINE_HEATING_POINTS = 5
OAK_HEATING_POINTS = 8
AUCTION_TYPE_FLAG = 0
AUCTION_TIME = (7 * 86400 // 30)
CUSTOM_ITEM_GOLD_GILDING_FEE_PER_THOUSAND = 5
CUSTOM_ITEM_GOLD_RECOVERY_FEE_PER_THOUSAND = 5
AUCTION_TYPE_FLAG = 0
AUCTION_TYPE_ITEM = 1
AUCTION_TYPE_ACCOUNT = 2
NEW_AUCTION_FEE = 100000000
AUCTION_BID_FEE = 10000000
MIN_AUCTION_BASE_TICKS = 8
@ -424,29 +424,30 @@ class CCTest():
def create(self):
print('Creating wallets')
seeds = [
'teardrop owls later width skater gadget different pegs yard ahead onslaught dynamite thorn espionage dwelt rural eels aimless shipped toaster shocking rounded maverick mystery thorn',
'geek origin industrial payment friendly physics width putty beyond addicted rogue metro midst anvil unplugs tequila efficient feast elapse liquid degrees smuggled also bawled tequila',
'tidy heron aching outbreak terminal inorganic nexus umpire economics auctions hope soapy hive vigilant hunter tadpoles hippo southern observant rabbits asked vector gimmick godfather heron',
'foyer mittens gaze vocal dwindling unnoticed pimple foolish sword stacking unveil fuming husband bodies exit mugged omnibus jump whale sanity loincloth menu bite cactus vocal',
'journal vitals technical dying dice taken evicted essential pepper dented psychic vaults oatmeal pairing wrong request damp rugged buffet lids bias pouch ladder leisure rugged',
[0, 'teardrop owls later width skater gadget different pegs yard ahead onslaught dynamite thorn espionage dwelt rural eels aimless shipped toaster shocking rounded maverick mystery thorn'],
[1, 'geek origin industrial payment friendly physics width putty beyond addicted rogue metro midst anvil unplugs tequila efficient feast elapse liquid degrees smuggled also bawled tequila'],
[2, 'tidy heron aching outbreak terminal inorganic nexus umpire economics auctions hope soapy hive vigilant hunter tadpoles hippo southern observant rabbits asked vector gimmick godfather heron'],
[3, 'foyer mittens gaze vocal dwindling unnoticed pimple foolish sword stacking unveil fuming husband bodies exit mugged omnibus jump whale sanity loincloth menu bite cactus vocal'],
[4, 'journal vitals technical dying dice taken evicted essential pepper dented psychic vaults oatmeal pairing wrong request damp rugged buffet lids bias pouch ladder leisure rugged'],
[6, 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted']
]
self.wallet = [None] * len(seeds)
self.pkeys = [None] * len(seeds)
for i in range(len(seeds)):
self.wallet[i] = Wallet(idx = i)
self.wallet[i] = Wallet(idx = seeds[i][0])
# close the wallet if any, will throw if none is loaded
try: self.wallet[i].close_wallet()
except: pass
res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i])
res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i][1])
res = self.wallet[i].cc_get_info()
self.pkeys[i] = res.cc_pkey
if not self.using_existing_chain:
ok = False
try: res = self.wallet[i].cc_get_info()
except: ok = True
if i == 3: # we're restoring the game account, which is pre-created
ok = not ok
assert ok
res = self.wallet[i].cc_get_info()
if seeds[i][0] == 3: # we're restoring the game account, which is pre-created
assert res.account_id == 2
else:
assert res.account_id == 0
self.wallet[i].set_daemon('127.0.0.1:18182')
self.daemon = Daemon(idx = 2)
if self.using_existing_chain:
@ -472,7 +473,8 @@ class CCTest():
['TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 500], # wallet[1]
['TF1MMBerc1QPyAGKFnREmBkQZ8Ujg6ZVkdJNseCoHebyXpF4adjr8r8PfcbRrDP2LhcJ7KLZV5Efgxb7MiXwFsxw6h8eUxa8s7b', 660], # wallet[3]
['TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1000], # wallet[2]
['TF1MMA4mMyUGkR373BQYWhkssgXWPuWdSauDXiRLJEmSXiJKbw3um94tDxogJShqXHt51a8UBotBRXuMvjFjaxSumjRXDrY7wSm', 0], # wallet[4]
['TF1MMA4mMyUGkR373BQYWhkssgXWPuWdSauDXiRLJEmSXiJKbw3um94tDxogJShqXHt51a8UBotBRXuMvjFjaxSumjRXDrY7wSm', 10], # wallet[4]
['TF1MM6BaRvBXH5Y4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJMnhZ9P', 10], # wallet[5]
]:
self.generate_blocks(data[0], data[1])
blocks_mined += data[1]
@ -2896,9 +2898,9 @@ class CCTest():
# too long
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], MAX_AUCTION_BASE_TICKS + 1))
# bad name
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, "aaaa\n"))
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, 0, "aaaa\n"))
# bad description
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, "", "\01"))
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, 0, "", "\01"))
# unsorted items
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_LABOUR, 'amount': 10}, {'object': ITEM_STONE, 'amount': 10}]))
# duplicated item
@ -2910,7 +2912,7 @@ class CCTest():
assert res.balance == expected_balances[i]
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
res = self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, "title", "This is\nits description")
res = self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, 8200, "title", "This is\nits description")
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
expected_balances[2] -= res.fee
expected_balances[2] -= NEW_AUCTION_FEE
@ -2932,6 +2934,9 @@ class CCTest():
auction_id = res.auctions[-1].id
assert res.auctions[-1].title == "title"
assert res.auctions[-1].description == "This is\nits description"
assert res.auctions[-1].reserve_price == 8200
assert 'bids' not in res.auctions[-1] or len(res.auctions[-1].bids) == 0
assert 'keys_' not in res.auctions[-1] or len(res.auctions[-1].keys_) == 0
# wait till past timeout
for i in range(8 + 1):
@ -2941,6 +2946,12 @@ class CCTest():
res = daemon.cc_get_auctions()
assert len(res.auctions) == num_auctions_at_start + 1
# can't bid below reserve price
self.assert_exception(lambda: self.wallet[2].cc_auction_bid(auction_id, 6000))
# account bids cannot be used on non account auctions
self.assert_exception(lambda: self.wallet[2].cc_account_auction_bid(auction_id, 12345, True))
# buy it on the cheap
res = self.wallet[2].cc_auction_bid(auction_id, 12345)
expected_balances[2] -= res.fee
@ -3146,6 +3157,359 @@ class CCTest():
for e in f.items_:
assert e.type != item_id
print('Testing account auctions')
expected_balances = [None, None, None, None]
expected_item_balances = [None, None, None, None]
account_id = [None, None, None, None]
for i in range(4): # last wallet doesn't have an account
self.wallet[i].refresh()
res = self.wallet[i].cc_get_info()
account_id[i] = res.account_id
res = daemon.cc_get_account(account_id[i])
expected_balances[i] = res.balance
expected_item_balances[i] = []
if 'item_balances' in res:
for e in res.item_balances:
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
res = self.wallet[4].get_balance()
expected_wallet4_balance = res.balance
res = self.wallet[5].get_balance()
expected_wallet5_balance = res.balance
res = daemon.cc_get_trustee_balances()
assert 'balances' not in res or len(res.balances) == 0
# get account 0 keys
res = daemon.cc_get_account(account_id[0])
pmspk0 = res.pmspk
pmvpk0 = res.pmvpk
self.wallet[0].refresh()
res = self.wallet[0].cc_get_info()
assert res.account_id == account_id[0]
assert res.cc_balance > 0
self.wallet[5].refresh()
res = self.wallet[5].cc_get_info()
assert res.account_id == 0
assert res.cc_balance == 0
# bad amount
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 0}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0"))
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 2}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0"))
# bad account
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': 0, 'amount': 1}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0"))
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[1], 'amount': 1}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0"))
# not one entry
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0"))
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 1}, {'object': account_id[0], 'amount': 1}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0"))
# invalid base ticks
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 1}], MIN_AUCTION_BASE_TICKS - 1, reserve_price = 45000, title = "Acc0", description = "Account 0"))
self.assert_exception(lambda: self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 1}], MAX_AUCTION_BASE_TICKS + 1, reserve_price = 45000, title = "Acc0", description = "Account 0"))
res = self.wallet[0].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 1}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0")
expected_balances[0] -= res.fee + NEW_AUCTION_FEE
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_auctions()
assert len(res.auctions) > 0
auction = res.auctions[-1]
assert auction.id > 0
assert auction.seller == account_id[0]
assert auction.type == AUCTION_TYPE_ACCOUNT
assert auction.entries == [{'object': account_id[0], 'amount': 1}]
assert auction.mortgage == 0
assert auction.reserve_price == 45000
assert auction.title == "Acc0"
assert auction.description == "Account 0"
assert auction.bid_account == 0
assert auction.bid_pkey in ["", "0"*64]
assert auction.bid_price == 0
assert not auction.overtime
assert 'bids' not in auction or len(auction.bids) == 0
assert len(auction.keys_) == 2 # two dummy keys to backup original account keys
assert len(auction.keys_[0]) == 3
assert auction.keys_[0]['pkey'] == "0" * 64
assert auction.keys_[0]['pmspk'] == self.pkeys[0]
assert auction.keys_[0]['pmvpk'] == "0" * 64
assert len(auction.keys_[1]) == 3
assert auction.keys_[1]['pkey'] == "f" * 64
assert auction.keys_[1]['pmspk'] == pmspk0
assert auction.keys_[1]['pmvpk'] == pmvpk0
auction_id = auction.id
# the account may not be used while being auctioned
self.assert_exception(lambda: self.wallet[0].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 5}]))
# wallets with an account may not bid on an account auction
self.assert_exception(lambda: self.wallet[2].cc_account_auction_bid(auction_id, 48000, True))
# more than balance
self.assert_exception(lambda: self.wallet[4].cc_account_auction_bid(auction_id, 480000000000, True))
res = self.wallet[4].cc_account_auction_bid(auction_id, 48000, True)
expected_wallet4_balance -= sum([fee for fee in res.fee_list]) + 48000 + AUCTION_BID_FEE
self.deposits += 48000 + AUCTION_BID_FEE
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_auctions(include_bid_history = True)
assert len(res.auctions) > 0
auction = res.auctions[-1]
assert auction.id == auction_id
assert auction.bid_account == 0
assert auction.bid_pkey == self.pkeys[4]
assert auction.bid_price == 48000
assert not auction.overtime
assert len(auction.bids) == 1
assert len(auction.keys_) == 3
assert auction.keys_[1].pkey == self.pkeys[4]
res = daemon.cc_get_trustee_balances()
assert len(res.balances) == 1
assert res.balances[0].pkey == self.pkeys[4]
assert res.balances[0].locked == 48000
assert res.balances[0].unlocked == 0
res = daemon.cc_get_trustee_balance(self.pkeys[4])
assert res.locked == 48000
assert res.unlocked == 0
res = daemon.cc_get_trustee_balance(self.pkeys[5])
assert res.locked == 0
assert res.unlocked == 0
# keys must be omitted on subsequent bids
self.assert_exception(lambda: self.wallet[4].cc_account_auction_bid(auction_id, 3000, True))
res = self.wallet[4].cc_account_auction_bid(auction_id, 3000, False)
expected_wallet4_balance -= sum([fee for fee in res.fee_list]) + 3000 + AUCTION_BID_FEE
self.deposits += 3000 + AUCTION_BID_FEE
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_auctions(include_bid_history = True)
assert len(res.auctions) > 0
auction = res.auctions[-1]
assert auction.id == auction_id
assert auction.bid_account == 0
assert auction.bid_pkey == self.pkeys[4]
assert auction.bid_price == 51000
assert not auction.overtime
assert len(auction.bids) == 2
assert len(auction.keys_) == 3
res = daemon.cc_get_trustee_balances()
assert len(res.balances) == 1
assert res.balances[0].pkey == self.pkeys[4]
assert res.balances[0].locked == 51000
assert res.balances[0].unlocked == 0
# another bidder
self.assert_exception(lambda: self.wallet[5].cc_account_auction_bid(auction_id, 50000, True)) # not highest bid
self.assert_exception(lambda: self.wallet[5].cc_account_auction_bid(auction_id, 56000, False)) # no keys
res = self.wallet[5].cc_account_auction_bid(auction_id, 56000, True)
expected_wallet5_balance -= sum([fee for fee in res.fee_list]) + 56000 + AUCTION_BID_FEE
self.deposits += 56000 + AUCTION_BID_FEE
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_auctions(include_bid_history = True)
assert len(res.auctions) > 0
auction = res.auctions[-1]
assert auction.id == auction_id
assert auction.bid_account == 0
assert auction.bid_pkey == self.pkeys[5]
assert auction.bid_price == 56000
assert not auction.overtime
assert len(auction.bids) == 3
assert len(auction.keys_) == 4
res = daemon.cc_get_trustee_balances()
assert len(res.balances) == 2
idx4 = 0 if res.balances[0].pkey == self.pkeys[4] else 1
assert res.balances[idx4].pkey == self.pkeys[4]
assert res.balances[idx4].locked == 51000
assert res.balances[idx4].unlocked == 0
assert res.balances[1-idx4].pkey == self.pkeys[5]
assert res.balances[1-idx4].locked == 56000
assert res.balances[1-idx4].unlocked == 0
# we can't withdraw funds held in trust, there's nothing unlocked there
self.assert_exception(lambda: self.wallet[4].cc_withdraw(1, True))
self.assert_exception(lambda: self.wallet[5].cc_withdraw(1, True))
# check balances
for i in range(4):
res = daemon.cc_get_account(account_id[i])
assert res.balance == expected_balances[i]
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
res = self.wallet[4].get_balance()
assert res.balance == expected_wallet4_balance
res = self.wallet[5].get_balance()
assert res.balance == expected_wallet5_balance
# wait till auction end
ended = False
for i in range(MIN_AUCTION_BASE_TICKS + 3):
# pass an update
res = daemon.get_info()
height = res.height
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
res = daemon.cc_get_auctions()
if 'auctions' not in res or [x for x in res.auctions if x.id == auction_id] == []:
ended = True
break
assert ended
# check money and account are transfered and usable
res = daemon.cc_get_trustee_balances()
assert len(res.balances) == 2
idx4 = 0 if res.balances[0].pkey == self.pkeys[4] else 1
assert res.balances[idx4].pkey == self.pkeys[4]
assert res.balances[idx4].locked == 0
assert res.balances[idx4].unlocked == 51000
assert res.balances[1-idx4].pkey == self.pkeys[0]
assert res.balances[1-idx4].locked == 0
assert res.balances[1-idx4].unlocked == 56000
res = daemon.cc_get_account(account_id[0])
assert res.public_key == self.pkeys[5]
assert res.pmspk != pmspk0
assert res.pmvpk != pmvpk0
self.wallet[0].refresh()
res = self.wallet[0].cc_get_info()
assert res.account_id == 0
assert res.cc_balance == 0
self.wallet[5].refresh()
res = self.wallet[5].cc_get_info()
assert res.account_id == account_id[0]
assert res.cc_balance > 0
# check control was really transfered
res = daemon.cc_get_account(account_id[0])
assert res.balance > 100000000 # so we don't fail the buy below from lack of money, but from lack of control
self.assert_exception(lambda: self.wallet[0].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 5}]))
self.wallet[5].refresh()
res = self.wallet[5].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 5}])
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
# auction it back to avoid upsetting the remaining tests
res = self.wallet[5].cc_create_auction(AUCTION_TYPE_ACCOUNT, [{'object': account_id[0], 'amount': 1}], MIN_AUCTION_BASE_TICKS, reserve_price = 45000, title = "Acc0", description = "Account 0")
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_auctions()
auction_id = res.auctions[-1].id
res = self.wallet[0].cc_account_auction_bid(auction_id, 50000, True)
self.deposits += 50000 + AUCTION_BID_FEE
# wait till auction end
ended = False
for i in range(MIN_AUCTION_BASE_TICKS + 3):
# pass an update
res = daemon.get_info()
height = res.height
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
res = daemon.cc_get_account(account_id[0])
assert res.public_key == self.pkeys[0]
assert res.pmspk == pmspk0
assert res.pmvpk == pmvpk0
# first auction:
# 0 sells
# 4 bids 48k + 3k == 51k
# 5 bids 56k
# -> 0: +56k
# -> 4: +51k
# -> 5: 0
# second auction:
# 5 sells
# 0 bids 50k
# -> 5: +50k
# 0: 0
# final:
# 0: +56k
# 4: +51k
# 5: +50k
# everyone can withdraw their funds held in trust
res = daemon.cc_get_trustee_balances()
assert len(res.balances) == 3
res = daemon.cc_get_trustee_balance(self.pkeys[0])
assert res.locked == 0
assert res.unlocked == 56000
res = daemon.cc_get_trustee_balance(self.pkeys[4])
assert res.locked == 0
assert res.unlocked == 51000 # failed bid
res = daemon.cc_get_trustee_balance(self.pkeys[5])
assert res.locked == 0
assert res.unlocked == 50000
res = self.wallet[0].cc_withdraw(50000, True)
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
self.deposits -= 50000
res = self.wallet[4].cc_withdraw(40000, True)
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
expected_wallet4_balance -= sum([fee for fee in res.fee_list])
expected_wallet4_balance += 40000
self.deposits -= 40000
res = daemon.cc_get_trustee_balances()
assert len(res.balances) == 3
res = daemon.cc_get_trustee_balance(self.pkeys[0])
assert res.locked == 0
assert res.unlocked == 6000
res = daemon.cc_get_trustee_balance(self.pkeys[4])
assert res.locked == 0
assert res.unlocked == 11000
res = daemon.cc_get_trustee_balance(self.pkeys[5])
assert res.locked == 0
assert res.unlocked == 50000
self.assert_exception(lambda: self.wallet[0].cc_withdraw(6001, True))
res = self.wallet[0].cc_withdraw(6000, True)
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
self.deposits -= 6000
self.assert_exception(lambda: self.wallet[4].cc_withdraw(11001, True))
res = self.wallet[4].cc_withdraw(11000, True)
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
expected_wallet4_balance -= sum([fee for fee in res.fee_list])
expected_wallet4_balance += 11000
self.deposits -= 11000
self.assert_exception(lambda: self.wallet[5].cc_withdraw(50001, True))
res = self.wallet[5].cc_withdraw(50000, True)
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
expected_wallet5_balance -= sum([fee for fee in res.fee_list])
expected_wallet5_balance += 50000
self.deposits -= 50000
res = daemon.cc_get_trustee_balances()
assert 'balances' not in res or len(res.balances) == 0
res = daemon.cc_get_trustee_balance(self.pkeys[0])
assert res.locked == 0
assert res.unlocked == 0
res = daemon.cc_get_trustee_balance(self.pkeys[4])
assert res.locked == 0
assert res.unlocked == 0
res = daemon.cc_get_trustee_balance(self.pkeys[5])
assert res.locked == 0
assert res.unlocked == 0
res = self.wallet[4].get_balance()
assert res.balance == expected_wallet4_balance
res = self.wallet[5].get_balance()
assert res.balance == expected_wallet5_balance
def test_trading(self):
daemon = self.daemon
@ -7986,10 +8350,8 @@ script {
invitation = res.invitation
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
ok = False
try: res = self.wallet[4].cc_get_info()
except: ok = True
assert ok
res = self.wallet[4].cc_get_info()
assert res.account_id == 0
# can't redeem if we already have an account
ok = False
@ -8027,10 +8389,8 @@ script {
assert ok
self.wallet[4].refresh()
ok = False
try: res = self.wallet[4].cc_get_info()
except: ok = True
assert ok
res = self.wallet[4].cc_get_info()
assert res.account_id == 0
# can do it again if popped
daemon.flush_txpool()
@ -11497,6 +11857,12 @@ script {
except:
pass
gold_in_trust = 0
res = daemon.cc_get_trustee_balances()
if 'balances' in res:
for e in res.balances:
gold_in_trust += e.locked + e.unlocked
game_subsidy = 0
res = daemon.get_info()
height = res.height
@ -11505,7 +11871,7 @@ script {
D = self.deposits
S = game_subsidy
B = gold_balance_available + gold_balance_reserved + gold_balance_in_coins + gold_balance_in_custom_items + gold_balance_reserved_in_coins + gold_balance_reserved_in_custom_items
B = gold_balance_available + gold_balance_reserved + gold_balance_in_coins + gold_balance_in_custom_items + gold_balance_reserved_in_coins + gold_balance_reserved_in_custom_items + gold_in_trust
F = game_fees
if D + S != B + F:
@ -11517,6 +11883,7 @@ script {
print('Gold in custom items balance: ' + str(gold_balance_in_custom_items / 1e8))
print('Gold in reserved coins balance: ' + str(gold_balance_reserved_in_coins / 1e8))
print('Gold in reserved custom items balance: ' + str(gold_balance_reserved_in_custom_items / 1e8))
print('Gold in trust: ' + str(gold_in_trust / 1e8))
print('Game subsidy: ' + str(game_subsidy / 1e8))
print('D: ' + str(D / 1e8))
@ -11781,13 +12148,13 @@ class Guard:
for i in [2, 3, 4]:
Daemon(idx = i).out_peers(0)
Daemon(idx = i).in_peers(0)
for i in [0, 1, 2, 3, 4]:
for i in [0, 1, 2, 3, 6]:
Wallet(idx = i).auto_refresh(False)
def __exit__(self, exc_type, exc_value, traceback):
for i in [2, 3, 4]:
Daemon(idx = i).out_peers(8)
Daemon(idx = i).in_peers(8)
for i in [0, 1, 2, 3, 4]:
for i in [0, 1, 2, 3, 6]:
Wallet(idx = i).set_daemon('127.0.0.1:18180')
Wallet(idx = i).auto_refresh(True)

View File

@ -46,10 +46,10 @@ except:
# three local online monerods connected to each other
N_MONERODS = 5
# 5 wallets connected to the main offline monerod
# 6 wallets connected to the main offline monerod
# a wallet connected to the first local online monerod
# 1 offline wallet
N_WALLETS = 6
N_WALLETS = 7
WALLET_DIRECTORY = builddir + "/functional-tests-directory"
FUNCTIONAL_TESTS_DIRECTORY = builddir + "/tests/functional_tests"
@ -73,6 +73,7 @@ wallet_extra = [
["--daemon-port", "18180"],
["--daemon-port", "18182"],
["--offline"],
["--daemon-port", "18180"],
]
command_lines = []

View File

@ -3088,6 +3088,10 @@ TEST(cc, type_tags)
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x4a);
cmd = cryptonote::cc_command_coru_jeopardy_pick_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x4b);
cmd = cryptonote::cc_command_withdraw_trustee_balance_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x4c);
cmd = cryptonote::cc_command_account_auction_bid_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x4d);
}
TEST(cc, staff)

View File

@ -1549,3 +1549,24 @@ class Daemon(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_get_coru_tournaments)
def cc_get_trustee_balances(self):
cc_get_trustee_balances = {
'method': 'cc_get_trustee_balances',
'params': {
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_get_trustee_balances)
def cc_get_trustee_balance(self, pkey):
cc_get_trustee_balance = {
'method': 'cc_get_trustee_balance',
'params': {
'pkey': pkey,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_get_trustee_balance)

View File

@ -121,6 +121,7 @@ def get_daemon_state(daemon):
state['epochs'] = daemon.cc_get_epochs()
state['coru_games'] = daemon.cc_get_coru_games(active_only = False)
state['coru_tournaments'] = daemon.cc_get_coru_tournaments(active_only = False)
state['trustee_balances'] = daemon.cc_get_trustee_balances()
return state
def backup_daemon_blockchain(daemon, tag = "backup"):

View File

@ -33,7 +33,7 @@ import json
class Response(dict):
def __init__(self, d):
for k in d.keys():
k_field = 'items_' if k == 'items' else k # readonly predefined field by that name
k_field = 'items_' if k == 'items' else 'keys_' if k == 'keys' else k # readonly predefined field by those names
if type(d[k]) == dict:
self[k_field] = Response(d[k])
elif type(d[k]) == list:

View File

@ -1118,11 +1118,12 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(cc_deposit)
def cc_withdraw(self, amount, priority = 0, get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
def cc_withdraw(self, amount, trustee = False, priority = 0, get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
cc_withdraw = {
'method': 'cc_withdraw',
'params': {
'amount': amount,
'trustee': trustee,
'priority': priority,
'get_tx_key' : get_tx_key,
'do_not_relay' : do_not_relay,
@ -1991,13 +1992,14 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(cc_carve_runestone)
def cc_create_auction(self, type, entries, base_ticks, title = "", description = "", priority = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
def cc_create_auction(self, type, entries, base_ticks, reserve_price = 0, title = "", description = "", priority = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
cc_create_auction = {
'method': 'cc_create_auction',
'params': {
'type': type,
'entries': entries,
'base_ticks': base_ticks,
'reserve_price': reserve_price,
'title': title,
'description': description,
'priority': priority,
@ -2552,3 +2554,16 @@ class Wallet(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_coru_jeopardy_pick)
def cc_account_auction_bid(self, auction, price_increase, first):
cc_account_auction_bid = {
'method': 'cc_account_auction_bid',
'params': {
'auction' : auction,
'price_increase' : price_increase,
'first' : first,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_account_auction_bid)