buying blocks in game

This commit is contained in:
Crypto City 2019-08-10 16:16:30 +00:00
parent 43ce9e2471
commit 822d3796a1
18 changed files with 502 additions and 74 deletions

View File

@ -44,21 +44,44 @@ void cc_command_handler_buy_blocks::get_in_out(const cryptonote::cc_command_t &c
uint64_t cc_command_handler_buy_blocks::get_cost(const cryptonote::cc_command_t &cmd) const
{
const cryptonote::cc_command_buy_blocks_t &buy_blocks = boost::get<cryptonote::cc_command_buy_blocks_t>(cmd);
return last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
uint64_t cost = 0;
for (const auto &e: buy_blocks.entries)
{
uint64_t entry_cost = last_resort_block_cost[e.type] * e.amount;
if (entry_cost > std::numeric_limits<uint64_t>::max() - cost)
{
MERROR("buy_blocks command cost overflow");
return std::numeric_limits<uint64_t>::max();
}
cost += entry_cost;
}
return cost;
}
bool cc_command_handler_buy_blocks::check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, uint32_t cc_account) const
{
const cryptonote::cc_command_buy_blocks_t &buy_blocks = boost::get<cryptonote::cc_command_buy_blocks_t>(cmd);
CHECK_AND_ASSERT_MES(buy_blocks.type != 0, false, "Buy order for block type 0");
CHECK_AND_ASSERT_MES(buy_blocks.amount > 0, false, "Buy order for 0 blocks");
CHECK_AND_ASSERT_MES(last_resort_block_cost[buy_blocks.type] > 0, false, "Trying to buy unallocated block type " + std::to_string(buy_blocks.type));
for (const auto &e: buy_blocks.entries)
{
CHECK_AND_ASSERT_MES(e.type != 0, false, "Buy order for block type 0");
CHECK_AND_ASSERT_MES(e.amount > 0, false, "Buy order for 0 blocks");
CHECK_AND_ASSERT_MES(last_resort_block_cost[e.type] > 0, false, "Trying to buy unallocated block type " + std::to_string(e.type));
}
bool present[256] = {false};
for (const auto &e: buy_blocks.entries)
{
CHECK_AND_ASSERT_MES(!present[e.type], false, "Buy order for the same block more than once");
present[e.type] = true;
}
crypto::public_key public_key;
uint64_t balance;
uint32_t block_balances[256];
std::vector<uint32_t> flags;
CHECK_AND_ASSERT_MES(db.get_cc_account_data(cc_account, public_key, balance, block_balances, flags), false, "Failed to get account data");
CHECK_AND_ASSERT_MES(block_balances[buy_blocks.type] <= std::numeric_limits<uint32_t>::max() - buy_blocks.amount, false, "Balance would overflow");
for (const auto &e: buy_blocks.entries)
{
CHECK_AND_ASSERT_MES(block_balances[e.type] <= std::numeric_limits<uint32_t>::max() - e.amount, false, "Balance would overflow");
}
return true;
}
@ -72,11 +95,16 @@ bool cc_command_handler_buy_blocks::execute(cryptonote::BlockchainDB &db, const
uint32_t treasury;
uint64_t cost;
cost = last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
cost = 0;
for (const auto &e: buy_blocks.entries)
cost += last_resort_block_cost[e.type] * e.amount;
CHECK_AND_ASSERT_MES(db.get_cc_account_data(cc_account, public_key, balance, block_balances, flags), false, "Failed to get account data");
CHECK_AND_ASSERT_MES(block_balances[buy_blocks.type] <= std::numeric_limits<uint32_t>::max() - buy_blocks.amount, false, "Balance would overflow");
block_balances[buy_blocks.type] += buy_blocks.amount;
for (const auto &e: buy_blocks.entries)
{
CHECK_AND_ASSERT_MES(block_balances[e.type] <= std::numeric_limits<uint32_t>::max() - e.amount, false, "Balance would overflow");
block_balances[e.type] += e.amount;
}
db.set_cc_account_block_balances(cc_account, block_balances);
balance -= cost;
db.set_cc_account_balance(cc_account, balance);
@ -99,11 +127,16 @@ bool cc_command_handler_buy_blocks::revert(cryptonote::BlockchainDB &db, const c
uint32_t treasury;
uint64_t cost;
cost = last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
cost = 0;
for (const auto &e: buy_blocks.entries)
cost += last_resort_block_cost[e.type] * e.amount;
CHECK_AND_ASSERT_MES(db.get_cc_account_data(cc_account, public_key, balance, block_balances, flags), false, "Failed to get account data");
CHECK_AND_ASSERT_MES(block_balances[buy_blocks.type] >= buy_blocks.amount, false, "Balance would underflow");
block_balances[buy_blocks.type] -= buy_blocks.amount;
for (const auto &e: buy_blocks.entries)
{
CHECK_AND_ASSERT_MES(block_balances[e.type] >= e.amount, false, "Balance would underflow");
block_balances[e.type] -= e.amount;
}
db.set_cc_account_block_balances(cc_account, block_balances);
CHECK_AND_ASSERT_MES(cost <= std::numeric_limits<uint64_t>::max() - balance, false, "Balance would overflow");

View File

@ -113,12 +113,21 @@ namespace cryptonote
struct cc_command_buy_blocks_t
{
uint8_t type;
uint32_t amount;
struct entry_t
{
uint8_t type;
uint32_t amount;
BEGIN_SERIALIZE_OBJECT()
FIELD(type)
VARINT_FIELD(amount);
END_SERIALIZE()
};
std::vector<entry_t> entries;
BEGIN_SERIALIZE_OBJECT()
FIELD(type)
VARINT_FIELD(amount)
FIELD(entries)
END_SERIALIZE()
};

View File

@ -34,6 +34,7 @@ set(game_sources
game-state.cc
shadable-window.cc
shade-button.cc
ui-buyblocks.cc
ui-notifier.cc
ui-urho3d.cc)
@ -45,6 +46,7 @@ set(game_headers
quadtree.h
shadable-window.h
shade-button.h
ui-buyblocks.h
ui-notifier.h
ui-urho3d.h)

View File

@ -31,6 +31,7 @@ void PlayerState::update(const std::shared_ptr<tools::wallet2> &w)
else
{
*this = PlayerState();
has_wallet = true;
// continue to fill up what we can
}
wallet_balance = w->balance(0);

View File

@ -533,18 +533,21 @@ bool GameWalletInternal::deposit(uint64_t amount, bool confirmed)
tools::wallet_keys_unlocker unlocker(*w, tools::password_container(password));
uint32_t fake_outs_count = w->adjust_mixin(0);
std::vector<tools::wallet2::pending_tx> ptx_vector = w->create_transactions_2(dsts, boost::none, cc_dest, fake_outs_count, 0 /* unlock_time */, priority, {}, 0, {});
if (ptx_vector.size() > 1)
try
{
new MessageBox(context_, "More than one transaction is needed. CC deposit/withdrawal should be one transaction only. Consolidate your outputs first by sending to yourself.");
return false;
std::vector<tools::wallet2::pending_tx> ptx_vector = w->create_transactions_2(dsts, boost::none, cc_dest, fake_outs_count, 0 /* unlock_time */, priority, {}, 0, {});
if (ptx_vector.size() > 1)
{
new MessageBox(context_, "More than one transaction is needed. CC deposit/withdrawal should be one transaction only. Consolidate your outputs first by sending to yourself.");
return false;
}
if (ptx_vector.empty())
{
new MessageBox(context_, "No outputs found, or daemon is not ready");
return false;
}
w->commit_tx(ptx_vector);
}
if (ptx_vector.empty())
{
new MessageBox(context_, "No outputs found, or daemon is not ready");
return false;
}
try { w->commit_tx(ptx_vector); }
catch (const std::exception &e) { new MessageBox(context_, String("Error creation transaction: ") + e.what()); return false; }
return true;
}

View File

@ -91,6 +91,7 @@ public:
void HandleDeposit(StringHash eventType, VariantMap& eventData);
void HandleWithdraw(StringHash eventType, VariantMap& eventData);
void HandleBuy(StringHash eventType, VariantMap& eventData);
void HandleBuyBlocks(StringHash eventType, VariantMap& eventData);
void HandleAddBlock(StringHash eventType, VariantMap& eventData);
void HandleRemoveBlock(StringHash eventType, VariantMap& eventData);
void HandleApproveBuild(StringHash eventType, VariantMap& eventData);
@ -343,6 +344,7 @@ void CryptoCityUrho3D::SetupUI()
SubscribeToEvent(ui, E_CRYPTOCITY_DEPOSIT, URHO3D_HANDLER(CryptoCityUrho3D, HandleDeposit));
SubscribeToEvent(ui, E_CRYPTOCITY_WITHDRAW, URHO3D_HANDLER(CryptoCityUrho3D, HandleWithdraw));
SubscribeToEvent(ui, E_CRYPTOCITY_BUY, URHO3D_HANDLER(CryptoCityUrho3D, HandleBuy));
SubscribeToEvent(ui, E_CRYPTOCITY_BUY_BLOCKS, URHO3D_HANDLER(CryptoCityUrho3D, HandleBuyBlocks));
SubscribeToEvent(ui, E_CRYPTOCITY_ADD_BLOCK, URHO3D_HANDLER(CryptoCityUrho3D, HandleAddBlock));
SubscribeToEvent(ui, E_CRYPTOCITY_REMOVE_BLOCK, URHO3D_HANDLER(CryptoCityUrho3D, HandleRemoveBlock));
SubscribeToEvent(ui, E_CRYPTOCITY_APPROVE_BUILD, URHO3D_HANDLER(CryptoCityUrho3D, HandleApproveBuild));
@ -841,6 +843,25 @@ void CryptoCityUrho3D::HandleBuy(StringHash eventType, VariantMap& eventData)
wallet->send_command(cmd);
}
void CryptoCityUrho3D::HandleBuyBlocks(StringHash eventType, VariantMap& eventData)
{
if (!wallet || !wallet->wallet())
{
new MessageBox(context_, "No wallet loaded - load a wallet to be able to buy blocks");
return;
}
cryptonote::cc_command_buy_blocks_t cmd;
const std::vector<std::pair<uint8_t, uint32_t>> *v = (const std::vector<std::pair<uint8_t, uint32_t>>*)eventData[BuyBlocks::P_QUANTITIES].GetVoidPtr();
for (const auto &q: *v)
{
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = q.first;
e.amount = q.second;
cmd.entries.push_back(e);
}
wallet->send_command(cmd);
}
void CryptoCityUrho3D::HandleAddBlock(StringHash eventType, VariantMap& eventData)
{
UnsetFocus();

View File

@ -37,16 +37,6 @@ BlockMaterial materials[256] =
},
{
2,
"water",
64, 64, 192, 1,
0,
1,
1,
4,
1,
},
{
3,
"wood",
60, 40, 10, 1,
1,
@ -55,6 +45,16 @@ BlockMaterial materials[256] =
1,
4,
},
{
3,
"water",
64, 64, 192, 1,
0,
1,
1,
4,
1,
},
};
bool encode_single_type(uint8_t src_type, uint16_t n_src_types, uint8_t *encoded_types, uint16_t *encoded_types_len)

View File

@ -2,6 +2,7 @@
#define CRYPTO_CITY_TYPES_H
#include <stdint.h>
#include <vector>
#include <deque>
#include <set>
#include <Urho3D/Container/RefCounted.h>

231
src/game/ui-buyblocks.cc Normal file
View File

@ -0,0 +1,231 @@
#include <limits.h>
#include <limits>
#include "Urho3D/Core/Context.h"
#include "Urho3D/Resource/ResourceCache.h"
#include "Urho3D/UI/UI.h"
#include "Urho3D/UI/UIEvents.h"
#include "Urho3D/UI/Window.h"
#include "Urho3D/UI/DropDownList.h"
#include "Urho3D/UI/LineEdit.h"
#include "Urho3D/UI/Text.h"
#include "Urho3D/UI/Button.h"
#include "Urho3D/UI/MessageBox.h"
#include "Urho3D/UI/ListView.h"
#include "game/map.h"
#include "ui-buyblocks.h"
using namespace Urho3D;
UIBuyBlocksDialog::UIBuyBlocksDialog(Context *ctx):
Object(ctx)
{
auto root = ctx->GetSubsystem<UI>()->GetRoot();
auto* cache = ctx->GetSubsystem<ResourceCache>();
auto* style = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
root->SetDefaultStyle(style);
window = root->CreateChild<Window>();
window->SetName("UIBuyBlocksDialog");
window->SetMinWidth(280);
window->SetLayout(LM_VERTICAL, 6, IntRect(6, 6, 6, 6));
window->SetAlignment(HA_CENTER, VA_CENTER);
window->SetStyleAuto(style);
// Create Window 'titlebar' container
auto* titleBar = new UIElement(context_);
titleBar->SetMinSize(0, 24);
titleBar->SetVerticalAlignment(VA_TOP);
titleBar->SetLayoutMode(LM_HORIZONTAL);
// Create the Window title Text
auto *windowTitle_ = new Text(context_);
windowTitle_->SetName("WindowTitle");
windowTitle_->SetText("Select blocks to buy:");
windowTitle_->SetStyleAuto(style);
// Create the Window's close button
auto* buttonClose = new Button(context_);
buttonClose->SetName("CloseButton");
buttonClose->SetStyle("CloseButton");
// Add the controls to the title bar
titleBar->AddChild(windowTitle_);
titleBar->AddChild(buttonClose);
// Add the title bar to the Window
window->AddChild(titleBar);
// contents
column = new UIElement(ctx);
column->SetLayout(LM_VERTICAL, 6, IntRect(0, 0, 0, 0));
column->SetStyleAuto(style);
window->AddChild(column);
// + button
UIElement *AddRowLayout = new UIElement(ctx);
AddRowLayout->SetStyleAuto(style);
AddRowLayout->SetLayout(LM_HORIZONTAL, 6, IntRect(0, 0, 0, 0));
column->AddChild(AddRowLayout);
auto* buttonAddRow = new Button(context_);
buttonAddRow->SetName("AddRow");
buttonAddRow->SetMinHeight(24);
buttonAddRow->SetMinWidth(48);
buttonAddRow->SetStyleAuto(style);
Text *textAddRow = new Text(context_);
textAddRow->SetText(" + ");
textAddRow->SetAlignment(HA_CENTER, VA_CENTER);
textAddRow->SetStyleAuto(style);
buttonAddRow->AddChild(textAddRow);
AddRowLayout->AddChild(buttonAddRow);
AddRow();
// OK/cancel buttons
auto* horiz = new UIElement(context_);
horiz->SetLayout(LM_HORIZONTAL, 6, IntRect(0, 6, 0, 0));
window->AddChild(horiz);
// OK
auto* buttonOK = new Button(context_);
buttonOK->SetName("OK");
buttonOK->SetMinHeight(24);
buttonOK->SetStyleAuto(style);
horiz->AddChild(buttonOK);
Text *textOK = new Text(context_);
textOK->SetText("OK");
textOK->SetAlignment(HA_CENTER, VA_CENTER);
textOK->SetStyleAuto(style);
buttonOK->AddChild(textOK);
// Cancel
auto* buttonCancel = new Button(context_);
buttonCancel->SetName("Cancel");
buttonCancel->SetMinHeight(24);
buttonCancel->SetStyleAuto(style);
horiz->AddChild(buttonCancel);
Text *textCancel = new Text(context_);
textCancel->SetText("Cancel");
textCancel->SetAlignment(HA_CENTER, VA_CENTER);
textCancel->SetStyleAuto(style);
buttonCancel->AddChild(textCancel);
//const IntVector2 size = window->GetSize();
window->SetPosition(0, 0);
window->SetModal(true);
buttonClose->SetStyle("CloseButton");
SubscribeToEvent(window, E_MODALCHANGED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleCancel));
SubscribeToEvent(buttonAddRow, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleAddRow));
SubscribeToEvent(buttonOK, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleOK));
SubscribeToEvent(buttonCancel, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleCancel));
SubscribeToEvent(buttonClose, E_RELEASED, URHO3D_HANDLER(UIBuyBlocksDialog, HandleCancel));
AddRef();
}
UIBuyBlocksDialog::~UIBuyBlocksDialog()
{
if (window)
window->Remove();
}
void UIBuyBlocksDialog::RegisterObject(Context* context)
{
context->RegisterFactory<UIBuyBlocksDialog>();
}
void UIBuyBlocksDialog::AddRow()
{
auto* cache = context_->GetSubsystem<ResourceCache>();
auto* style = cache->GetResource<XMLFile>("UI/DefaultStyle.xml");
auto *row = new UIElement(context_);
row->SetStyleAuto(style);
row->SetMinHeight(20);
row->SetLayout(LM_HORIZONTAL, 6, IntRect(0, 0, 0, 0));
column->InsertChild(typeWidgets.size(), row);
SharedPtr<DropDownList> typeWidget(new DropDownList(context_));
typeWidget->SetName("MaterialDropDown");
typeWidget->SetResizePopup(true);
// fill list
unsigned int idx = 0;
for (int i = 1; i < 256; ++i)
{
const BlockMaterial &m = materials[i];
if (!m.name)
continue;
types[idx++] = i;
Text *t = new Text(context_);
t->SetText(m.name);
t->SetStyleAuto(style);
typeWidget->AddItem(t);
}
row->AddChild(typeWidget);
typeWidget->SetStyleAuto(style);
SharedPtr<LineEdit> amountWidget(new LineEdit(context_));
amountWidget->SetStyleAuto(style);
amountWidget->SetText("0");
row->AddChild(amountWidget);
typeWidget->SetSelection(0);
typeWidgets.push_back(std::move(typeWidget));
amountWidgets.push_back(std::move(amountWidget));
}
void UIBuyBlocksDialog::HandleOK(StringHash eventType, VariantMap& eventData)
{
std::vector<std::pair<uint8_t, uint32_t>> quantities;
for (size_t i = 0; i < typeWidgets.size(); ++i)
{
unsigned sel = typeWidgets[i]->GetSelection();
if (sel >= 256)
{
new MessageBox(context_, "Internal error: bad item index");
return;
}
char *endptr = NULL;
errno = 0;
unsigned long ul = strtoul(amountWidgets[i]->GetText().CString(), &endptr, 10);
if ((endptr && *endptr) || (ul == ULONG_MAX && errno) || ul > std::numeric_limits<uint32_t>::max())
{
new MessageBox(context_, "Invalid amount");
return;
}
const uint8_t sel8 = types[sel];
if (sel8 == 0 || !materials[sel8].name)
{
new MessageBox(context_, "Internal error: bad item");
return;
}
const uint32_t amount = ul;
quantities.push_back(std::make_pair(sel8, amount));
}
VariantMap& newEventData = GetEventDataMap();
newEventData[BuyBlocksOkayed::P_QUANTITIES] = &quantities;
SendEvent(E_BUY_BLOCKS_OKAYED, newEventData);
// Self destruct
ReleaseRef();
}
void UIBuyBlocksDialog::HandleAddRow(StringHash eventType, VariantMap& eventData)
{
AddRow();
}
void UIBuyBlocksDialog::HandleCancel(StringHash eventType, VariantMap& eventData)
{
VariantMap& newEventData = GetEventDataMap();
SendEvent(E_BUY_BLOCKS_CANCELLED, newEventData);
// Self destruct
ReleaseRef();
}

45
src/game/ui-buyblocks.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef UI_BUY_BLOCKS_H
#define UI_BUY_BLOCKS_H
#include <vector>
#include <Urho3D/Core/Object.h>
#include <Urho3D/Container/Str.h>
#include <Urho3D/Container/Ptr.h>
#include <Urho3D/Math/StringHash.h>
namespace Urho3D
{
class Context;
class Window;
class DropDownList;
class LineEdit;
}
URHO3D_EVENT(E_BUY_BLOCKS_OKAYED, BuyBlocksOkayed) { URHO3D_PARAM(P_QUANTITIES, Quantities); }
URHO3D_EVENT(E_BUY_BLOCKS_CANCELLED, BuyBlocksCancelled) {}
class UIBuyBlocksDialog: public Urho3D::Object
{
URHO3D_OBJECT(UIBuyBlocksDialog, Object);
public:
UIBuyBlocksDialog(Urho3D::Context *ctx);
virtual ~UIBuyBlocksDialog() override;
static void RegisterObject(Urho3D::Context* context);
private:
void AddRow();
void HandleAddRow(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleOK(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleCancel(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
private:
Urho3D::SharedPtr<Urho3D::Window> window;
Urho3D::SharedPtr<Urho3D::UIElement> column;
std::vector<Urho3D::SharedPtr<Urho3D::DropDownList>> typeWidgets;
std::vector<Urho3D::SharedPtr<Urho3D::LineEdit>> amountWidgets;
uint8_t types[256];
};
#endif

View File

@ -4,6 +4,7 @@
#include <Urho3D/UI/UIEvents.h>
#include <Urho3D/Graphics/Graphics.h>
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "ui-buyblocks.h"
#include "cc/cc.h"
#include "ui-urho3d.h"
@ -327,12 +328,14 @@ void UIUrho3D::CreateActionsWindow()
Button *removeBlockButton = AddButton(w, "Remove block");
Button *approveBuildButton = AddButton(w, "Approve build");
Button *abandonBuildButton = AddButton(w, "Abandon build");
Button *buyBlocksButton = AddButton(w, "Buy blocks");
SubscribeToEvent(buyButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleBuy));
SubscribeToEvent(addBlockButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleAddBlock));
SubscribeToEvent(removeBlockButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleRemoveBlock));
SubscribeToEvent(approveBuildButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleApproveBuild));
SubscribeToEvent(abandonBuildButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleAbandonBuild));
SubscribeToEvent(buyBlocksButton, E_RELEASED, URHO3D_HANDLER(UIUrho3D, HandleBuyBlocks));
actionsWindow->SetPosition(0, selectionWindow->GetHeight() + playerWindow->GetHeight() + displayWindow->GetHeight());
}
@ -528,6 +531,14 @@ void UIUrho3D::HandleAbandonBuild(StringHash eventType, VariantMap& eventData)
SendEvent(E_CRYPTOCITY_ABANDON_BUILD, noEventData);
}
void UIUrho3D::HandleBuyBlocks(StringHash eventType, VariantMap& eventData)
{
auto *d = new UIBuyBlocksDialog(context_);
SubscribeToEvent(d, E_BUY_BLOCKS_OKAYED, [this](StringHash eventType, VariantMap& eventData) {
SendEvent(E_CRYPTOCITY_BUY_BLOCKS, eventData);
});
}
void UIUrho3D::HandleDisplayNormal(StringHash eventType, VariantMap& eventData)
{
VariantMap noEventData;

View File

@ -18,6 +18,7 @@ URHO3D_EVENT(E_CRYPTOCITY_LOAD_WALLET, LoadWallet) {}
URHO3D_EVENT(E_CRYPTOCITY_DEPOSIT, Deposit) { URHO3D_PARAM(P_AMOUNT, Amount); /*, uint64_t */ }
URHO3D_EVENT(E_CRYPTOCITY_WITHDRAW, Withdraw) { URHO3D_PARAM(P_AMOUNT, Amount); /* uint64_t */ }
URHO3D_EVENT(E_CRYPTOCITY_BUY, Buy) {}
URHO3D_EVENT(E_CRYPTOCITY_BUY_BLOCKS, BuyBlocks) { URHO3D_PARAM(P_QUANTITIES, Quantities); /* vector */ }
URHO3D_EVENT(E_CRYPTOCITY_ADD_BLOCK, AddBlock) {}
URHO3D_EVENT(E_CRYPTOCITY_REMOVE_BLOCK, RemoveBlock) {}
URHO3D_EVENT(E_CRYPTOCITY_APPROVE_BUILD, ApproveBuild) {}
@ -58,6 +59,7 @@ private:
void HandleRemoveBlock(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleApproveBuild(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleAbandonBuild(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleBuyBlocks(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleDisplayNormal(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleDisplayLand(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleMaterialSelected(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);

View File

@ -2652,8 +2652,10 @@ bool simple_wallet::cc_buy_blocks(const std::vector<std::string> &args_)
message_writer() << tr("Price per block: ") << cryptonote::print_money(last_resort_block_cost[type]);
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = type;
cmd.amount = amount;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = type;
e.amount = amount;
cmd.entries.push_back(e);
return send_command(cmd);
}

View File

@ -4240,8 +4240,10 @@ namespace tools
try
{
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = req.type;
cmd.amount = req.amount;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = req.type;
e.amount = req.amount;
cmd.entries.push_back(e);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_cc_transactions(cmd, priority);
if (ptx_vector.empty())

View File

@ -441,19 +441,21 @@ bool gen_cc_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
events.push_back(tx);
txs_hashes.push_back(get_transaction_hash(tx));
cryptonote::cc_command_buy_blocks_t buy_blocks;
for (int i = 1; i <= 2; ++i)
{
cryptonote::cc_command_buy_blocks_t buy_blocks;
buy_blocks.type = i;
buy_blocks.amount = 20 - 10 * (i-1);
fee = BARE_TX_FEE;
expected_balance[cc_account - 4] -= last_resort_block_cost[buy_blocks.type] * buy_blocks.amount + fee;
expected_treasury_balance += last_resort_block_cost[buy_blocks.type] * buy_blocks.amount;
r = construct_bare_tx(sending_account.get_keys(), cc_account, buy_blocks, fee, tx);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
events.push_back(tx);
txs_hashes.push_back(get_transaction_hash(tx));
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = i;
e.amount = 20 - 10 * (i-1);
buy_blocks.entries.push_back(e);
expected_balance[cc_account - 4] -= last_resort_block_cost[e.type] * e.amount + fee;
expected_treasury_balance += last_resort_block_cost[e.type] * e.amount;
}
fee = BARE_TX_FEE;
r = construct_bare_tx(sending_account.get_keys(), cc_account, buy_blocks, fee, tx);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
events.push_back(tx);
txs_hashes.push_back(get_transaction_hash(tx));
cryptonote::block blk;
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account,
@ -1337,19 +1339,23 @@ bool gen_cc_tx_valid_cc_bare_buy_blocks::generate(std::vector<test_event_entry>&
blocks_cost = 0;
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = 1;
cmd.amount = 80;
blocks_cost += last_resort_block_cost[cmd.type] * cmd.amount;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = 1;
e.amount = 80;
cmd.entries.push_back(e);
blocks_cost += last_resort_block_cost[e.type] * e.amount;
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
cmd.type = 2;
cmd.amount = 180;
blocks_cost += last_resort_block_cost[cmd.type] * cmd.amount;
e.type = 2;
e.amount = 180;
cmd.entries[0] = e;
blocks_cost += last_resort_block_cost[e.type] * e.amount;
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
cmd.type = 1;
cmd.amount = 40;
blocks_cost += last_resort_block_cost[cmd.type] * cmd.amount;
e.type = 1;
e.amount = 40;
cmd.entries[0] = e;
blocks_cost += last_resort_block_cost[e.type] * e.amount;
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, valid, NULL, NULL);
@ -1374,8 +1380,10 @@ bool gen_cc_tx_invalid_cc_bare_buy_blocks_type_0::generate(std::vector<test_even
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = 0;
cmd.amount = 1;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = 0;
e.amount = 1;
cmd.entries.push_back(e);
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
@ -1389,8 +1397,10 @@ bool gen_cc_tx_invalid_cc_bare_buy_blocks_amount_0::generate(std::vector<test_ev
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = 1;
cmd.amount = 0;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = 1;
e.amount = 0;
cmd.entries.push_back(e);
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
@ -1404,10 +1414,49 @@ bool gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow::generate(std::vector
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = 1;
cmd.amount = 0x1fffffff;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = 1;
e.amount = 0x1fffffff;
cmd.entries.push_back(e);
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
}
bool gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate::generate(std::vector<test_event_entry>& events) const
{
init_cc_test_accounts();
const unsigned int mixin = 10;
const uint64_t amount_paid = 0;
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
cryptonote::cc_command_buy_blocks_t cmd;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = 1;
e.amount = 30000000;
cmd.entries.push_back(e);
e.type = 2;
e.amount = 30000000;
cmd.entries.push_back(e);
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
}
bool gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type::generate(std::vector<test_event_entry>& events) const
{
init_cc_test_accounts();
const unsigned int mixin = 10;
const uint64_t amount_paid = 0;
std::vector<std::tuple<uint32_t, std::string, cryptonote::cc_command_t, uint64_t>> cmds;
cryptonote::cc_command_buy_blocks_t cmd;
cryptonote::cc_command_buy_blocks_t::entry_t e;
e.type = 1;
e.amount = 0x100;
cmd.entries.push_back(e);
cmd.entries.push_back(e);
cmds.push_back(std::make_tuple(4, "", cmd, BARE_TX_FEE));
return generate_with(events, boost::none, boost::none, prep_create_accounts, cmds.size(), mixin, amount_paid, true, cmds, false, invalid, NULL, NULL);
}

View File

@ -358,3 +358,15 @@ struct gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow: public gen_cc_tx_v
bool generate(std::vector<test_event_entry>& events) const;
};
template<> struct get_test_options<gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow>: public get_test_options<gen_cc_tx_validation_base> {};
struct gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate: public gen_cc_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
template<> struct get_test_options<gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate>: public get_test_options<gen_cc_tx_validation_base> {};
struct gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type: public gen_cc_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
template<> struct get_test_options<gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type>: public get_test_options<gen_cc_tx_validation_base> {};

View File

@ -303,6 +303,8 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_type_0);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_amount_0);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_balance_overflow_in_aggregate);
GENERATE_AND_PLAY(gen_cc_tx_invalid_cc_bare_buy_blocks_duplicate_type);
el::Level level = (failed_tests.empty() ? el::Level::Info : el::Level::Error);
if (!list_tests)

View File

@ -457,14 +457,15 @@ TEST(cc_command, build)
TEST(cc_command, buy_blocks)
{
cryptonote::cc_command_buy_blocks_t cmd;
cmd.type = 1;
cmd.amount = 1;
cmd.entries.resize(1);
cmd.entries[0].type = 1;
cmd.entries[0].amount = 1;
uint64_t c1 = cc::get_cc_command_cost(cmd);
ASSERT_GT(c1, 0);
cmd.amount = 50;
cmd.entries[0].amount = 50;
uint64_t c50 = cc::get_cc_command_cost(cmd);
ASSERT_EQ(c50, 50 * c1);
cmd.amount = std::numeric_limits<uint32_t>::max();
cmd.entries[0].amount = std::numeric_limits<uint32_t>::max();
uint64_t cmax32 = cc::get_cc_command_cost(cmd);
ASSERT_EQ(cmax32, std::numeric_limits<uint32_t>::max() * c1);
uint64_t cc_in = (uint64_t)-1, cc_out = (uint64_t)-1;
@ -779,20 +780,21 @@ TEST(cc_command, execute_buy_blocks)
create_account.public_key = keys.pub;
create_account.amount = CRYPTONOTE_CC_NEW_ACCOUNT_FEE + 1000000000000;
setup.push_back(std::make_pair(1, create_account));
buy_blocks.entries.resize(1);
// good
buy_blocks.type = 1;
buy_blocks.amount = 1;
buy_blocks.entries[0].type = 1;
buy_blocks.entries[0].amount = 1;
test_commands(true, 4, setup, buy_blocks, "valid");
// cannot buy block 0
buy_blocks.type = 0;
buy_blocks.amount = 1;
buy_blocks.entries[0].type = 0;
buy_blocks.entries[0].amount = 1;
test_commands(false, 4, setup, buy_blocks, "block 0");
// cannot buy 0 blocks
buy_blocks.type = 1;
buy_blocks.amount = 0;
buy_blocks.entries[0].type = 1;
buy_blocks.entries[0].amount = 0;
test_commands(false, 4, setup, buy_blocks, "0 blocks");
}