simplewallet: add sanity check to staking commands (#123)

This commit is contained in:
jcktm 2018-08-08 14:15:44 +10:00
parent 591fda78f0
commit 79406a28a0
5 changed files with 97 additions and 36 deletions

View File

@ -50,7 +50,6 @@
#include "common/int-util.h"
#include "common/threadpool.h"
#include "common/boost_serialization_helper.h"
#include "common/exp2.h"
#include "warnings.h"
#include "crypto/hash.h"
#include "cryptonote_core.h"
@ -851,20 +850,6 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
m_difficulty_for_next_block = diff;
return diff;
}
//------------------------------------------------------------------
uint64_t Blockchain::get_staking_requirement(uint64_t height) const
{
if (m_nettype == TESTNET)
return COIN * 100;
uint64_t height_adjusted = height-129600;
uint64_t base = 10000 * COIN;
uint64_t variable = (35000.0 * COIN) / loki_exp2(height_adjusted/129600.0);
uint64_t linear_up = 5 * COIN * height / 2592;
uint64_t flat = 15000 * COIN;
return std::min(30000 * COIN,
std::max(base + variable, height < 3628800 ? linear_up : flat));
}
//------------------------------------------------------------------
// This function removes blocks from the blockchain until it gets to the
// position where the blockchain switch started and then re-adds the blocks

View File

@ -320,13 +320,6 @@ namespace cryptonote
*/
difficulty_type get_difficulty_for_next_block();
/**
* @brief returns the staking requirement for the block at height
*
* @return the target
*/
uint64_t get_staking_requirement(uint64_t height) const;
/**
* @brief adds a block to the blockchain
*
@ -781,6 +774,12 @@ namespace cryptonote
*/
void safesyncmode(const bool onoff);
/**
* @brief Get the nettype
* @return the nettype
*/
network_type nettype() const { return m_nettype; }
/**
* @brief set whether or not to show/print time statistics
*

View File

@ -38,6 +38,7 @@
#include "common/scoped_message_writer.h"
#include "common/i18n.h"
#include "quorum_cop.h"
#include "common/exp2.h"
#include "service_node_list.h"
@ -298,7 +299,7 @@ namespace service_nodes
// check the initial contribution exists
info.staking_requirement = m_blockchain.get_staking_requirement(block_height);
info.staking_requirement = get_staking_requirement(m_blockchain.nettype(), block_height);
cryptonote::account_public_address address;
uint64_t transferred = 0;
@ -1087,6 +1088,16 @@ namespace service_nodes
cmd = stream.str();
return true;
}
uint64_t get_staking_requirement(cryptonote::network_type m_nettype, uint64_t height)
{
if (m_nettype == cryptonote::TESTNET)
return COIN * 100;
uint64_t height_adjusted = height-129600;
uint64_t base = 10000 * COIN;
uint64_t variable = (35000.0 * COIN) / loki_exp2(height_adjusted/129600.0);
uint64_t linear_up = 5 * COIN * height / 2592;
uint64_t flat = 15000 * COIN;
return std::min(30000 * COIN, std::max(base + variable, height < 3628800 ? linear_up : flat));
}
}

View File

@ -258,6 +258,8 @@ namespace service_nodes
bool make_registration_cmd(cryptonote::network_type nettype, const std::vector<std::string> args, const crypto::public_key& service_node_pubkey,
const crypto::secret_key service_node_key, std::string &cmd, bool make_friendly);
uint64_t get_staking_requirement(cryptonote::network_type nettype, uint64_t height);
const static cryptonote::account_public_address null_address{ crypto::null_pkey, crypto::null_pkey };
}

View File

@ -4712,17 +4712,29 @@ bool simple_wallet::register_service_node(const std::vector<std::string> &args_)
size_t mixins = DEFAULT_MIX;
uint64_t unlock_block = 0;
uint64_t locked_blocks = STAKING_REQUIREMENT_LOCK_BLOCKS + STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS;
std::string err;
uint64_t bc_height = get_daemon_blockchain_height(err);
if (!err.empty())
uint64_t bc_height = m_wallet->get_daemon_blockchain_height(err);
if (!m_wallet->is_synced() || !err.empty() || bc_height < 10)
{
fail_msg_writer() << tr("failed to get blockchain height: ") << err;
return true;
if (!m_wallet->is_synced())
err = tr("daemon not finished syncing");
fail_msg_writer() << tr("unable to get network blockchain height from daemon: ") << err;
std::string height = input_line(tr("Please enter the current network block height: "));
try
{
bc_height = boost::lexical_cast<uint64_t>(height);
}
catch (const std::exception &e)
{
fail_msg_writer() << tr("Invalid block height");
return true;
}
}
unlock_block = bc_height + locked_blocks;
uint64_t unlock_block = bc_height + locked_blocks;
if (local_args.size() < 4)
{
@ -4793,6 +4805,19 @@ bool simple_wallet::register_service_node(const std::vector<std::string> &args_)
return true;
}
uint64_t expected_staking_requirement = std::max(
service_nodes::get_staking_requirement(m_wallet->nettype(), bc_height),
service_nodes::get_staking_requirement(m_wallet->nettype(), bc_height+STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS)
);
if (amount < expected_staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS)
{
fail_msg_writer() << tr("This staking amount is not enough and cannot be used for a registration");
fail_msg_writer() << tr("If it looks correct, please send a little bit extra to ensure that it is still correct when it makes it into a block");
fail_msg_writer() << tr("Please send at least: ") << print_money(expected_staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS);
return true;
}
LOCK_IDLE_SCOPE();
cryptonote::account_public_address address = addresses[0];
@ -4946,17 +4971,29 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
size_t mixins = DEFAULT_MIX;
uint64_t unlock_block = 0;
uint64_t locked_blocks = STAKING_REQUIREMENT_LOCK_BLOCKS + STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS;
std::string err;
uint64_t bc_height = get_daemon_blockchain_height(err);
if (!err.empty())
uint64_t bc_height = m_wallet->get_daemon_blockchain_height(err);
if (!m_wallet->is_synced() || !err.empty() || bc_height < 10)
{
fail_msg_writer() << tr("failed to get blockchain height: ") << err;
return true;
if (!m_wallet->is_synced())
err = tr("daemon not finished syncing");
fail_msg_writer() << tr("unable to get network blockchain height from daemon: ") << err;
std::string height = input_line(tr("Please enter the current network block height: "));
try
{
bc_height = boost::lexical_cast<uint64_t>(height);
}
catch (const std::exception &e)
{
fail_msg_writer() << tr("Invalid block height");
return true;
}
}
unlock_block = bc_height + locked_blocks;
uint64_t unlock_block = bc_height + locked_blocks;
if (local_args.size() < 2)
{
@ -4979,6 +5016,33 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
return true;
}
uint64_t expected_staking_requirement = std::max(
service_nodes::get_staking_requirement(m_wallet->nettype(), bc_height),
service_nodes::get_staking_requirement(m_wallet->nettype(), bc_height+STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS)
);
if (amount < expected_staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS)
{
std::stringstream prompt;
prompt << tr("This staking amount is not enough and cannot be used to stake") << '\n';
prompt << tr("If it looks correct, please send a little bit extra to ensure that it is still correct when it makes it into a block") << '\n';
prompt << tr("This warning was triggered because you sent less than: ") << print_money(expected_staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS) << tr(" loki\n");
prompt << tr("") << '\n';
prompt << tr("If this is not the first time you are making a contribution to this service node") << '\n';
prompt << tr("then it should be okay to top-up the amount you are contributing. This is also true") << '\n';
prompt << tr("if this address was specified in the service node registration.") << '\n';
prompt << tr("") << '\n';
prompt << tr("Most likely this is not the right amount to send. Only continue if you know what you are doing.") << '\n';
prompt << tr("\nDo you want to continue?");
std::string accepted = input_line(prompt.str());
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
{
fail_msg_writer() << tr("transaction cancelled.");
return true;
}
}
std::vector<uint8_t> extra;
add_service_node_pubkey_to_tx_extra(extra, service_node_key);