rate limiting for son deposit, withdrawal, pw change, tx settle operations
This commit is contained in:
parent
ae712122d4
commit
668f677867
4 changed files with 75 additions and 7 deletions
|
|
@ -12,6 +12,20 @@ namespace detail {
|
|||
class peerplays_sidechain_plugin_impl;
|
||||
}
|
||||
|
||||
struct son_proposal_type {
|
||||
son_proposal_type(int op, son_id_type son, object_id_type object) :
|
||||
op_type(op),
|
||||
son_id(son),
|
||||
object_id(object) {
|
||||
}
|
||||
int op_type;
|
||||
son_id_type son_id;
|
||||
object_id_type object_id;
|
||||
bool operator<(const son_proposal_type &other) const {
|
||||
return std::tie(op_type, son_id, object_id) < std::tie(other.op_type, other.son_id, other.object_id);
|
||||
}
|
||||
};
|
||||
|
||||
class peerplays_sidechain_plugin : public graphene::app::plugin {
|
||||
public:
|
||||
peerplays_sidechain_plugin();
|
||||
|
|
@ -34,6 +48,8 @@ public:
|
|||
bool is_son_deregistered(son_id_type son_id);
|
||||
fc::ecc::private_key get_private_key(son_id_type son_id);
|
||||
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
||||
void log_son_proposal_retry(int op_type, object_id_type object_id);
|
||||
bool can_son_participate(int op_type, object_id_type object_id);
|
||||
};
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ public:
|
|||
bool is_valid_son_proposal(const chain::proposal_object &proposal);
|
||||
fc::ecc::private_key get_private_key(son_id_type son_id);
|
||||
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
||||
void log_son_proposal_retry(int op_type, object_id_type object_id);
|
||||
bool can_son_participate(int op_type, object_id_type object_id);
|
||||
|
||||
void schedule_heartbeat_loop();
|
||||
void heartbeat_loop();
|
||||
|
|
@ -75,6 +77,8 @@ private:
|
|||
std::map<chain::public_key_type, fc::ecc::private_key> private_keys;
|
||||
fc::future<void> _heartbeat_task;
|
||||
fc::future<void> _son_processing_task;
|
||||
std::map<son_proposal_type, uint16_t> son_retry_count;
|
||||
uint16_t retries_threshold;
|
||||
|
||||
bool first_block_skipped;
|
||||
void on_applied_block(const signed_block &b);
|
||||
|
|
@ -130,6 +134,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
|||
cli.add_options()("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password");
|
||||
cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
||||
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
|
||||
cli.add_options()("sidechain-retry-threshold", bpo::value<uint16_t>()->default_value(15), "Sidechain retry throttling threshold");
|
||||
cfg.add(cli);
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +174,8 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
|||
}
|
||||
config_ready_son = config_ready_son && !private_keys.empty();
|
||||
}
|
||||
retries_threshold = options.at("sidechain-retry-threshold").as<uint16_t>();
|
||||
ilog("sidechain-retry-threshold: ${sidechain-retry-threshold}", ("sidechain-retry-threshold", retries_threshold));
|
||||
}
|
||||
if (!config_ready_son) {
|
||||
wlog("Haven't set up SON parameters");
|
||||
|
|
@ -449,6 +456,22 @@ bool peerplays_sidechain_plugin_impl::is_valid_son_proposal(const chain::proposa
|
|||
return false;
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::log_son_proposal_retry(int op_type, object_id_type object_id) {
|
||||
son_proposal_type prop_type(op_type, get_current_son_id(), object_id);
|
||||
auto itr = son_retry_count.find(prop_type);
|
||||
if (itr != son_retry_count.end()) {
|
||||
itr->second++;
|
||||
} else {
|
||||
son_retry_count[prop_type] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin_impl::can_son_participate(int op_type, object_id_type object_id) {
|
||||
son_proposal_type prop_type(op_type, get_current_son_id(), object_id);
|
||||
auto itr = son_retry_count.find(prop_type);
|
||||
return (itr == son_retry_count.end() || itr->second < retries_threshold);
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::approve_proposals() {
|
||||
|
||||
auto check_approve_proposal = [&](const chain::son_id_type &son_id, const chain::proposal_object &proposal) {
|
||||
|
|
@ -695,4 +718,12 @@ fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(chain::public_k
|
|||
return my->get_private_key(public_key);
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin::log_son_proposal_retry(int op_type, object_id_type object_id) {
|
||||
my->log_son_proposal_retry(op_type, object_id);
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin::can_son_participate(int op_type, object_id_type object_id) {
|
||||
return my->can_son_participate(op_type, object_id);
|
||||
}
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ void sidechain_net_handler::process_proposals() {
|
|||
|
||||
int32_t op_idx_0 = -1;
|
||||
chain::operation op_obj_idx_0;
|
||||
object_id_type object_id;
|
||||
|
||||
if (po->proposed_transaction.operations.size() >= 1) {
|
||||
op_idx_0 = po->proposed_transaction.operations[0].which();
|
||||
|
|
@ -293,11 +294,13 @@ void sidechain_net_handler::process_proposals() {
|
|||
switch (op_idx_0) {
|
||||
case chain::operation::tag<chain::son_wallet_update_operation>::value: {
|
||||
should_process = (op_obj_idx_0.get<son_wallet_update_operation>().sidechain == sidechain);
|
||||
object_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
|
||||
break;
|
||||
}
|
||||
|
||||
case chain::operation::tag<chain::son_wallet_deposit_process_operation>::value: {
|
||||
son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get<son_wallet_deposit_process_operation>().son_wallet_deposit_id;
|
||||
object_id = swdo_id;
|
||||
const auto &idx = database.get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
|
||||
const auto swdo = idx.find(swdo_id);
|
||||
if (swdo != idx.end()) {
|
||||
|
|
@ -308,6 +311,7 @@ void sidechain_net_handler::process_proposals() {
|
|||
|
||||
case chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value: {
|
||||
son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get<son_wallet_withdraw_process_operation>().son_wallet_withdraw_id;
|
||||
object_id = swwo_id;
|
||||
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
||||
const auto swwo = idx.find(swwo_id);
|
||||
if (swwo != idx.end()) {
|
||||
|
|
@ -323,6 +327,7 @@ void sidechain_net_handler::process_proposals() {
|
|||
const auto sto = idx.find(st_id);
|
||||
if (sto != idx.end()) {
|
||||
should_process = ((sto->sidechain == sidechain) && (sto->status == sidechain_transaction_status::valid) && signer_expected(*sto, signer));
|
||||
object_id = sto->object_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -333,6 +338,7 @@ void sidechain_net_handler::process_proposals() {
|
|||
const auto sto = idx.find(st_id);
|
||||
if (sto != idx.end()) {
|
||||
should_process = (sto->sidechain == sidechain);
|
||||
object_id = sto->object_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -344,10 +350,14 @@ void sidechain_net_handler::process_proposals() {
|
|||
elog("==================================================");
|
||||
}
|
||||
|
||||
if (should_process) {
|
||||
if (should_process && (op_idx_0 == chain::operation::tag<chain::sidechain_transaction_sign_operation>::value || plugin.can_son_participate(op_idx_0, object_id))) {
|
||||
bool should_approve = process_proposal(*po);
|
||||
if (should_approve) {
|
||||
approve_proposal(po->id, plugin.get_current_son_id());
|
||||
if (approve_proposal(po->id, plugin.get_current_son_id())) {
|
||||
if (op_idx_0 != chain::operation::tag<chain::sidechain_transaction_sign_operation>::value) {
|
||||
plugin.log_son_proposal_retry(op_idx_0, object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -374,7 +384,7 @@ void sidechain_net_handler::process_deposits() {
|
|||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false));
|
||||
|
||||
std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_deposit_object &swdo) {
|
||||
if (swdo.id == object_id_type(0, 0, 0)) {
|
||||
if (swdo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id)) {
|
||||
return;
|
||||
}
|
||||
//Ignore the deposits which are not valid anymore, considered refunds.
|
||||
|
|
@ -392,6 +402,7 @@ void sidechain_net_handler::process_deposits() {
|
|||
wlog("Deposit not processed: ${swdo}", ("swdo", swdo));
|
||||
return;
|
||||
}
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -404,7 +415,7 @@ void sidechain_net_handler::process_withdrawals() {
|
|||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false));
|
||||
|
||||
std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_withdraw_object &swwo) {
|
||||
if (swwo.id == object_id_type(0, 0, 0)) {
|
||||
if (swwo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -416,6 +427,7 @@ void sidechain_net_handler::process_withdrawals() {
|
|||
wlog("Withdraw not processed: ${swwo}", ("swwo", swwo));
|
||||
return;
|
||||
}
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -514,6 +526,10 @@ void sidechain_net_handler::settle_sidechain_transactions() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!plugin.can_son_participate(chain::operation::tag<chain::sidechain_transaction_settle_operation>::value, sto.object_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ilog("Sidechain transaction to settle: ${sto}", ("sto", sto.id));
|
||||
|
||||
int64_t settle_amount = settle_sidechain_transaction(sto);
|
||||
|
|
@ -560,6 +576,7 @@ void sidechain_net_handler::settle_sidechain_transactions() {
|
|||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::sidechain_transaction_settle_operation>::value, sto.object_id);
|
||||
} catch (fc::exception &e) {
|
||||
elog("Sending proposal for sidechain transaction settle operation failed with exception ${e}", ("e", e.what()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1287,6 +1287,9 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
|||
boost::property_tree::ptree active_pw_pt;
|
||||
boost::property_tree::read_json(active_pw_ss, active_pw_pt);
|
||||
if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
|
||||
if (!plugin.can_son_participate(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
|
|
@ -1325,6 +1328,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
|||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
|
||||
} catch (fc::exception &e) {
|
||||
elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in a new issue